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

 更新时间:2020年12月02日 08:54:47   作者:yangyang  
这篇文章主要介绍了C#表达式树的基本用法讲解,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下

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

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

生成表达式树

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

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

通过API创建表达式树

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

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

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创建数字阶乘的表达式树:

//参数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的各个部分。

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委托类型,使用方法如下:

// 创建表达式树
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));

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

//创建表达式树的执行逻辑
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#表达式树的资料请关注脚本之家其它相关文章!

相关文章

  • C#获取机器码的方法详解(机器名,CPU编号,硬盘编号,网卡mac等)

    C#获取机器码的方法详解(机器名,CPU编号,硬盘编号,网卡mac等)

    这篇文章主要介绍了C#获取机器码的方法,结合实例形式详细分析了C#获取硬件机器名、CPU编号、硬盘编号、网卡mac等信息的相关实现方法,需要的朋友可以参考下
    2016-07-07
  • C# Path类---文件路径解读

    C# Path类---文件路径解读

    这篇文章主要介绍了C# Path类---文件路径,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • C#实现冻结Excel窗口以锁定行列或解除冻结

    C#实现冻结Excel窗口以锁定行列或解除冻结

    在处理大型Excel工作簿时,有时候我们需要在工作表中冻结窗格,这样可以在滚动查看数据的同时保持某些行或列固定不动,下面我们就来看看如何使用C#实现冻结Excel窗口吧
    2024-04-04
  • unity实现物体延时出现

    unity实现物体延时出现

    这篇文章主要为大家详细介绍了unity实现物体延时出现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • C#计算字符串哈希值(MD5、SHA)的方法小结

    C#计算字符串哈希值(MD5、SHA)的方法小结

    这篇文章主要介绍了C#计算字符串哈希值(MD5、SHA)的方法,以实例形式较为详细的分析总结了C#计算字符串哈希值的各种常用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • C# 线程简单介绍及使用详情

    C# 线程简单介绍及使用详情

    这篇文章主要介绍了C# 线程简单介绍及使用详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • C#使用iTextSharp库将图片转换为PDF

    C#使用iTextSharp库将图片转换为PDF

    iTextSharp 是一个开源的 .NET 库,主要用于创建和操作 PDF 文档,本文主要介绍了如何使用 C# 和 iTextSharp 将图片转换为 PDF 的功能,需要的可以参考下
    2024-12-12
  • C# Lambda表达式select()和where()的区别及用法

    C# Lambda表达式select()和where()的区别及用法

    这篇文章主要介绍了C# Lambda表达式select()和where()的区别及用法,select在linq中一般会用来提取最后筛选的元素集合,在lambda表达式中通常用where得到元素集合,需要的朋友可以参考下
    2023-07-07
  • WinForm中实现双向数据绑定的示例详解

    WinForm中实现双向数据绑定的示例详解

    在开发WinForm应用程序时,常常需要将数据模型与用户界面进行同步,传统的做法是手动监听UI变化并更新数据模型,这种方式不仅繁琐而且容易出错,为了解决这个问题,许多现代UI框架都支持双向数据绑定,本文介绍WinForm中实现双向数据绑定的示例,需要的朋友可以参考下
    2025-05-05
  • C# SMTP发送邮件的示例

    C# SMTP发送邮件的示例

    这篇文章主要介绍了C# SMTP发送邮件的示例,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下
    2020-12-12

最新评论