服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#表达式树的基本用法讲解

C#表达式树的基本用法讲解

2022-10-19 13:02yangyang C#

这篇文章主要介绍了C#表达式树的基本用法讲解,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下

   表达式树使用一种类似树的结构来表示代码,它的每个节点都是一个表达式,比如方法调用和x<y这样的二元运算等。我们可以对表达式树的内容进行编辑和运算,这样能够动态修改可执行代码,以及动态创建查询等。我们可以使用匿名lambda表达式或者C# API来创建表达式树。

   这一系列文章,主要是对C#表达式树的一种总结,基本知识参考MSDN的内容 这部分内容可以直接到MSDN上查看,后面的几篇文章主要分享一下,在工作中碰到的应用到表达式树的部分,谨做为记录和分享。

生成表达式树

通过lambda表达式创建表达式树
    可以通过将lambda表达式赋值给Expression<TDelegate>类型的变量,编译器可以自动生成创建该lambda表达式的表达式树。C#编译器只能从lambda表达式生成表达式树,只能是单行lambda表达式,不能解析多行lambda语句,如下,可以通过一下方式创建lambda表达式 num=>num<5的表达式树:

?
1
Expression<Func<int, bool>> lambda = num => num < 5;

通过API创建表达式树

   使用API创建表达式,需要使用Expression类,这个类包含了创建特定类型表达式树节点的静态工厂方法,比如表示参数的变量ParameterExpression,表示方法调用的MethodExpression。ParameterExpression,MethodExpression以及其他特定的表达式类型都在System.Linq.Expression命名空间里定义,这些类型都派生于Expression抽象类。

  下面的例子是使用API方式创建num=>num<5的lambda表达式对应的表达式树:

?
1
2
3
4
5
ParameterExpression numPara = Expression.Parameter(typeof(int), "num");//参数num
ConstantExpression five = Expression.Constant(5, typeof(int));//常数5
 
BinaryExpression numLessThanFive = Expression.LessThan(numPara, five);
Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numPara });

    从.NET Framework 4开始,表达式树API还支持赋值以及流程控制,比如循环,条件块和try ... catch块等。相对于通过lambda表达式创建表达式树,可以利用API创建更加复杂的表达式树,比如下面使用API创建数字阶乘的表达式树:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//参数value
ParameterExpression value = Expression.Parameter(typeof(int), "value");
//本地变量
ParameterExpression result = Expression.Parameter(typeof(int), "result");
//标签,用来跳出循环
LabelTarget label = Expression.Label(typeof(int));
//创建表达式块
BlockExpression block = Expression.Block(
 //添加本地参数result
 new[] { result },
 //result=1 赋值
 Expression.Assign(result, Expression.Constant(1)),
 //循环
 Expression.Loop(
  //循环条件
  Expression.IfThenElse(
   //如果 value>1
   Expression.GreaterThan(value, Expression.Constant(1)),
   //则 result*=value--;
   Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)),
   //否则跳出loop循环。跳到label的语句执行
   Expression.Break(label, result)
   ),
   label
  )
);
//编译表达式树
Func<int, int> factor = Expression.Lambda<Func<int, int>>(block, value).Compile();
//执行,输出结果120
Console.WriteLine(factor(5));

解析表达式树

  在获取了表达式树之后,如何获取表达式树的每一个部分,这个在有些情况下非常有用,下面这个例子展示了如何获取num=>num<5的各个部分。

?
1
2
3
4
5
6
7
8
Expression<Func<int, bool>> expreTree = num => num < 5;
 
ParameterExpression param = (ParameterExpression)expreTree.Parameters[0];//num
BinaryExpression operation = (BinaryExpression)expreTree.Body;//<
ParameterExpression left = (ParameterExpression)operation.Left;//num
ConstantExpression right = (ConstantExpression)operation.Right;//5
                //output Decomposed expression: num => num LessThan 5
Console.WriteLine("Decomposed expression:{0} = > {1} {2} {3}", param.Name, left.Name, operation.NodeType, right.Value);

编译表达式树

  Expression<TDelegate>类型有Compile方法,可以将表达式树编译成对应的TDelegate委托类型,使用方法如下:

?
1
2
3
4
5
6
7
8
// 创建表达式树
Expression<Func<int, bool>> expr = num => num < 5;
// 将表达式树编译成对应委托
Func<int, bool> result = expr.Compile();
//调用委托方法,输出True
Console.WriteLine(result(4));
//也可以直接编译后调用,输出True
Console.WriteLine(expr.Compile()(4));

再比如,下面例子演示了,创建一个表达式树,然后编译执行:

?
1
2
3
4
5
6
7
8
9
//创建表达式树的执行逻辑
BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D));
//创建表达式树
Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);
//编译表达式树
Func<double> compileExpression = le.Compile();
//执行lambda表达式,获得结果8
double result = compileExpression();
Console.WriteLine(result);

表达式树的修改

   表达式树是不可变对象(immutable),跟string类似,不能直接修改,只能复制一个然后重新构造。具体参考MSDN How to modify expression trees (C#).

结语

  本篇全部内容参考MSDN上表达式树部分的内容,如果有基础建议直接看,这里只是个人作为笔记,也是表达式树的最基础部分,后文会介绍表达式树的一些用法。

以上就是C#表达式树的基本用法讲解的详细内容,更多关于C#表达式树的资料请关注服务器之家其它相关文章!

原文链接:https://www.yycoding.xyz/post/2020/9/22/an-introduction-to-csharp-expression-tree-basic-usage

延伸 · 阅读

精彩推荐
  • C#C# 泛型参数转换

    C# 泛型参数转换

    本文介绍了C# 泛型参数转换的相关知识,具有很好的参考价值,下面跟着小编一起来看下吧...

    诺贝尔12272021-12-23
  • C#Unity实现图片轮播组件

    Unity实现图片轮播组件

    这篇文章主要为大家详细介绍了Unity实现图片轮播组件的相关方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    qq_2699950911882022-07-09
  • C#C#实现winform中RichTextBox在指定光标位置插入图片的方法

    C#实现winform中RichTextBox在指定光标位置插入图片的方法

    这篇文章主要介绍了C#实现winform中RichTextBox在指定光标位置插入图片的方法,涉及RichTextBox控件及剪切板的相关操作技巧,非常简单实用,需要的朋友可以参考下...

    aparche5442021-11-24
  • C#C#使用正则表达式隐藏手机号中间四位为*

    C#使用正则表达式隐藏手机号中间四位为*

    这篇文章主要介绍了C#使用正则表达式隐藏手机号中间四位为*的相关资料,需要的朋友可以参考下...

    qq_329153375922022-01-10
  • C#C#实现较为实用的SQLhelper

    C#实现较为实用的SQLhelper

    这篇文章主要为大家详细介绍了C#实现较为实用SQLhelper的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    天空的影子7652021-12-08
  • C#c# 接口使用实例

    c# 接口使用实例

    这篇文章主要介绍了c#接口使用的实例,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...

    莫得感情的代码机器9542022-09-27
  • C#C#中ListView控件实现窗体代码

    C#中ListView控件实现窗体代码

    这篇文章主要介绍了C#中ListView控件实现窗体的核心代码,非常不错,具有参考借鉴价值,对c#listview相关知识感兴趣的朋友一起学习吧...

    绯色梧桐绯色月6712021-12-06
  • C#在C#中如何使用正式表达式获取匹配所需数据

    在C#中如何使用正式表达式获取匹配所需数据

    本文给大家分享C#中如何使用正式表达式获取匹配所需数据 ,非常实用,对正则表达式获取匹配相关知识感兴趣的朋友一起学习吧...

    仙桃小白菜4912021-11-16