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");
 
bool res = lambda.Compile()(new SearchInfo() { Name = "6" }); // 结果 : false

注释: 为了能够了解 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#)的更多相关文章

  1. 介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql

    一.Expression2Sql介绍 Expression2Sql是一个可以将Expression表达式树解析成Transact-SQL的项目.简单易用,几分钟即可上手使用,因为博主在设计Expres ...

  2. 委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底

    本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function&l ...

  3. .net 系列:Expression表达式树、lambda、匿名委托 的使用

    首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static strin ...

  4. .net 系列:Expression表达式树、lambda、匿名委托 的使用【转】

    https://www.cnblogs.com/nicholashjh/p/7928205.html 首先定义一个泛型委托类型,如下: public delegate T Function<T& ...

  5. .NET技术-6.0. Expression 表达式树 生成 Lambda

    .NET技术-6.0. Expression 表达式树 生成 Lambda public static event Func<Student, bool> myevent; public ...

  6. Expression表达式树

    表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x < y 的二元运算 1.利用 Lambda 表达式创建表达式树 Expression<Fun ...

  7. 关于Expression表达式树的拼接

    最近在做项目中遇到一个问题,需求是这样的: 我要对已经存在的用户进行检索,可以根据用户的id 或者用户名其中的一部分字符来检索出来,这样就出现了三种情况 只有id,只有用户名中一部字符,或者全部都有. ...

  8. Expression 表达式树学习整理

    整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的来吧  它表示具有常量值的表达式 我们选建一个控制台应用程序 ConstantExpression _ ...

  9. (转)Expression 表达式树学习整理

    原文地址:http://www.cnblogs.com/li-peng/p/3154381.html 整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的 ...

随机推荐

  1. CodeForces 550B Preparing Olympiad(DFS回溯+暴力枚举)

    [题目链接]:click here~~ [题目大意] 一组题目的数目(n<=15),每一个题目有对应的难度,问你选择一定的题目(大于r个且小于l个)且选择后的题目里最小难度与最大难度差不小于x, ...

  2. Hadoop - YARN NodeManager 剖析

    一 概述         NodeManager是执行在单个节点上的代理,它管理Hadoop集群中单个计算节点,功能包含与ResourceManager保持通信,管理Container的生命周期.监控 ...

  3. C# Winform 模拟QQ新闻弹出框

    一开始做的时候,觉得这个太简单了.真心做的时候还是遇到了不少的坑啊. 1)循环播放新闻内容,建议使用showdialog(),不要用show(),不太好控制前后之间的停顿. 2)窗口的初始位置为有下角 ...

  4. jquery判断页面元素是否存在

    在传统的Javascript里,当我们对某个页面元素进行某种操作前,最好先判断这个元素是否存在.原因是对一个不存在的元素进行操作是不允许的. 例如: document.getElementById(& ...

  5. OpenGL编程(五)绘直线以及分析绘直线的算法

    这次主要实现在窗口上绘制点.线以及修改其属性,另外还会分析画直线的原理和相关算法. 1.在窗口指定位置画点 glBegin(GL_POINTS); glEnd(); 使用glBegin()和glEnd ...

  6. [LNOI2014]LCA 树链剖分 离线 前缀和 思维题

    题目描述:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每 ...

  7. TP5 模板渲染语法

    每次都要去网上找,又发现都不全.所以自己记录一下 volist:循环 {volist name="collection" id="v"} {/volist} i ...

  8. Java Web Application——servlet

    概述 是一个部署于web服务器中的实现了servlet接口的Java类,用于响应web请求 Web容器(也称为servlet容器)本质上是与servlet交互的Web服务器的组件.Web容器负责管理s ...

  9. Ubuntu 环境下的mysql 远程访问,redis 远程访问和设置密码 ,mongo 安装 ,设置用户密码,开启远程访问

    MySQL远程访问 1.编辑mysql配置文件,把其中bind-address = 127.0.0.1注释了 vi /etc/mysql/mysql.conf.d/mysqld.cnf 2.使用roo ...

  10. [CQOI2013]新Nim游戏(线性基)

    P4301 [CQOI2013]新Nim游戏 题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴. ...