Expression表达式树(C#)
Lambda表达式:
1.下面举例通过Lambda表达式创建了一个用于验证Name的Func委托。
//通过Lambda表达式创建一个对象的Name属性验证委托
Func<SearchInfo, bool> func = x => x.Name.Equals("");
/// <summary>
/// 测试类
/// </summary>
public class SearchInfo
{
public string Name { get; set; } public string Code { get; set; }
}
2.测试调用, 下面验证 "6" 是否和 "5" 相等, 结果false
//res=false
bool res = func(new SearchInfo() { Name = "" });
那么问题来了, 如果我希望验证的结果不是 "5" 而是其他的内容: "7","9" ...等等呢? ,
那么接下来封装一个Func, 允许自定义验证结果:
public static Func<SearchInfo, bool> Func(string arr)
{
return x => x.Name.Equals(arr); //这一步将Equals中校验的内容进行了参数封装
}
测试代码:
bool f1= Func("")(new SearchInfo() { Name = "" }); //true
bool f2 = Func("")(new SearchInfo() { Name = "" }); //false
bool f3 = Func("")(new SearchInfo() { Name = "" }); //false
如上所示, 我们成功的把Equals中的验证结果封装了起来。但是 !实际应用这还不够,
如果你要校验的不是Name 或是Code, Equals 变成其他 Contains呢?如下:
﹋﹊﹋﹊﹋﹊﹋﹊﹋分割线﹊﹋﹊﹋﹊﹋﹊﹋﹊
Expression(表达式树)
位于 System.Linq.Expressions 命名空间下, 下面介绍如何以上简单的示例创建一个动态的Expression, 类型参数为委托类型:
//
// 摘要:
// 将强类型化的 Lambda 表达式表示为表达式树形式的数据结构。 此类不能被继承。
//
// 类型参数:
// TDelegate:
// 该委托的类型, System.Linq.Expressions.Expression`1 表示。
public sealed class Expression<TDelegate> : LambdaExpression
{
//
// 摘要:
// 编译表达式树由描述为可执行代码的 lambda 表达式,并生成一个委托,表示 lambda 表达式。
//
// 返回结果:
// 类型的委托 TDelegate 表示所描述的已编译的 lambda 表达式 System.Linq.Expressions.Expression`1。
public TDelegate Compile();
//
// 摘要:
// 将生成一个委托,表示 lambda 表达式。
//
// 参数:
// debugInfoGenerator:
// 由编译器用于将标记序列点并添加批注的本地变量的调试信息生成器。
//
// 返回结果:
// 一个包含已编译的版本的 lambda 的委托。
public TDelegate Compile(DebugInfoGenerator debugInfoGenerator);
//
// 摘要:
// 创建一个新的表达式,它类似于此表达式,但使用所提供的子级。 如果所有子级均相同,它将返回此表达式。
//
// 参数:
// body:
// System.Linq.Expressions.LambdaExpression.Body 结果属性。
//
// parameters:
// System.Linq.Expressions.LambdaExpression.Parameters 结果属性。
//
// 返回结果:
// 如果子级未更改,则为此表达式;否则为具有已更新子级的表达式。
public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters);
protected internal override Expression Accept(ExpressionVisitor visitor);
}
示例(用表达式的形式):
注释: 为了能够了解 Expression<Func<SearchInfo, bool>> lambda = x => x.Name.Equals("5") 这段代码的结构,
接下来用 ILSpy 反编译, 查看到该代码生成了如下:
ParameterExpression parameterExpression = Expression.Parameter(typeof(SearchInfo), "x");
Expression<Func<SearchInfo, bool>> expression = Expression.Lambda<Func<SearchInfo, bool>>(Expression.Call(
Expression.Property(parameterExpression, (MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(get_Name()))),
(MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(Equals())),
new Expression[]
{
Expression.Constant("", typeof(string))
}), new ParameterExpression[]
{
parameterExpression
});
我们分解以上代码(先用数字标识):
1. ParameterExpression parameterExpression = Expression.Parameter(typeof(SearchInfo), "x"); 参数表达式
2. Expression.Property(parameterExpression, (MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(get_Name()))) 属性表达式
3. new Expression[] { Expression.Constant("5", typeof(string)) } 常数表达式
4. (MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(Equals())) 方法调用表达式
5. Expression.Lambda<Func<SearchInfo, bool>>(Expression.Call( 2, 4, 3), 1); 创建Lambda表达式
接下来回到最开始的Lambda表达式, 图解说明以上的代码分别代表Lambda表达式的每个部分:
理解上表达式生成的5个步骤, 接下来还原一个表达式完整的创建过程, 如下:
//1.创建参数表达式
ParameterExpression parameterExpression = Expression.Parameter(typeof(SearchInfo), "x"); //2.创建属性表达式
Expression proerty = Expression.Property(parameterExpression, typeof(SearchInfo).GetProperty("Name")); //3.创建常数表达式
ConstantExpression constantExpression = Expression.Constant("", typeof(string)); //4.创建方法调用表达式
MethodCallExpression toString = Expression.Call(
proerty,
typeof(SearchInfo).GetMethod("Equals"),
new Expression[] { constantExpression }); //5.创建Lambda表达式
Expression<Func<SearchInfo, bool>> lambda = Expression.Lambda<Func<SearchInfo, bool>>(toString, new ParameterExpression[]
{
parameterExpression
});
以上则是如何创建一个表达式树, 测试调用, 如下:
bool res = lambda.Compile()(new SearchInfo() { Name = "" }); // “5”!=“55” 结果: false
注: Compile() 为lambda的编译, 后面则才能进行参数的传递
基于类(Class)动态生成表达式:
/// <summary>
/// 测试类
/// </summary>
public class SearchInfo
{
public string Name { get; set; } public string Code { get; set; } public string Id { get; set; } public string Addr { get; set; } public string Res { get; set; }
}
public static Func<T, bool> GenerateExpression<T>(T searchModel) where T : class, new()
{
List<MethodCallExpression> mcList = new List<MethodCallExpression>();
Type type = searchModel.GetType();
ParameterExpression parameterExpression = Expression.Parameter(type, "x");
var pros = type.GetProperties();
foreach (var t in pros)
{
var objValue = t.GetValue(searchModel, null);
if (objValue != null)
{
Expression proerty = Expression.Property(parameterExpression, t);
ConstantExpression constantExpression = Expression.Constant(objValue, t.PropertyType);
mcList.Add(Expression.Call(proerty, typeof(string).GetMethod("Contains"), new Expression[] { constantExpression }));
}
} if (mcList.Count == )
return Expression.Lambda<Func<T, bool>>(Expression.Constant(true, typeof(bool)), new ParameterExpression[] { parameterExpression }).Compile();
else
return Expression.Lambda<Func<T, bool>>(MethodCall(mcList), new ParameterExpression[] { parameterExpression }).Compile();
} public static Expression MethodCall<T>(List<T> mcList) where T : MethodCallExpression
{
if (mcList.Count == ) return mcList[];
BinaryExpression binaryExpression = null;
for (int i = ; i < mcList.Count; i += )
{
if (i < mcList.Count - )
{
BinaryExpression binary = Expression.OrElse(mcList[i], mcList[i + ]);
if (binaryExpression != null)
binaryExpression = Expression.OrElse(binaryExpression, binary);
else
binaryExpression = binary;
}
}
if (mcList.Count % != )
return Expression.OrElse(binaryExpression, mcList[mcList.Count - ]);
else
return binaryExpression;
}
测试代码 :
static void Main(string[] args)
{
var func = GenerateExpression(new SearchInfo()); List<SearchInfo> List = new List<SearchInfo>();
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" });
List.Add(new SearchInfo() { Code = "", Id = "", Name = "", Addr = "", Res = "" }); var ii = List.Where(func).ToList(); //8个结果
}
Expression表达式树(C#)的更多相关文章
- 介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql
一.Expression2Sql介绍 Expression2Sql是一个可以将Expression表达式树解析成Transact-SQL的项目.简单易用,几分钟即可上手使用,因为博主在设计Expres ...
- 委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底
本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function&l ...
- .net 系列:Expression表达式树、lambda、匿名委托 的使用
首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static strin ...
- .net 系列:Expression表达式树、lambda、匿名委托 的使用【转】
https://www.cnblogs.com/nicholashjh/p/7928205.html 首先定义一个泛型委托类型,如下: public delegate T Function<T& ...
- .NET技术-6.0. Expression 表达式树 生成 Lambda
.NET技术-6.0. Expression 表达式树 生成 Lambda public static event Func<Student, bool> myevent; public ...
- Expression表达式树
表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x < y 的二元运算 1.利用 Lambda 表达式创建表达式树 Expression<Fun ...
- 关于Expression表达式树的拼接
最近在做项目中遇到一个问题,需求是这样的: 我要对已经存在的用户进行检索,可以根据用户的id 或者用户名其中的一部分字符来检索出来,这样就出现了三种情况 只有id,只有用户名中一部字符,或者全部都有. ...
- Expression 表达式树学习整理
整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的来吧 它表示具有常量值的表达式 我们选建一个控制台应用程序 ConstantExpression _ ...
- (转)Expression 表达式树学习整理
原文地址:http://www.cnblogs.com/li-peng/p/3154381.html 整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的 ...
随机推荐
- SVN管理工具的使用(实习第9天)
最后就是我进行提交代码的时候要记得写注释,自己写了那些方法要标明,或者自己修改了哪些功能也要表明.不然我会被骂的. 2>代码冲突解决的问题: 服务器上的代码跟自己代码改动的地方不同 这种情况比较 ...
- IIS访问站点,出现connection refused
排查后,发现是因为使用了代理导致的. 需要设置 Don't use the proxy server for local addresses.
- Getting Started with MongoDB (MongoDB Shell Edition)
https://docs.mongodb.com/getting-started/shell/ Overview Welcome to the Getting Started with MongoDB ...
- .Net配置虚拟域名
1.在IIS中配置和地址端口,和名称. 2.在hosts文件中加上地址匹配. 3.重启IIS管理网站. 就可以通过虚拟域名进行访问了.
- Session原理、安全以及最基本的Express和Redis实现
Session原理.安全以及最基本的Express和Redis实现 https://segmentfault.com/a/1190000002630691
- sicily 1000. LinkedList
Description template <typename E> class LinkedList { private: // inner class: linked-list ...
- POJ 1151 线段树+扫描线
题意:求矩形面积的并 思路: 注意是[l,mid][mid,r] 这是真正的线段了 就当扫描线模板使吧~ //By SiriusRen #include <cmath> #include ...
- 谈谈Vim中实用又好记的一些命令
本文的目的在于总结一些日常操作中比较实用.有规律的Vim命令,而不致于介绍一些基础的Vim知识,比如几种插入模式,hjkl移动命令,dd删除本行,p粘贴 等等,故对Vim基本知识不够熟悉的请参见其 ...
- ajax+h5实现文件上传,成功即显示缩略图。
官方参考文档: http://fex.baidu.com/webuploader/ 文件下载地址: https://github.com/fex-team/webuploader/releases/d ...
- bzoj1922 [SDOI2010]大陆争霸 分层图
问题描述 幻想历8012年5月12日深夜,斯普林·布拉泽降下神谕:“Trust me, earn eternal life.”克里斯军团士气大增.作为克里斯军团的主帅,你决定利用这一机会发动奇袭,一举 ...