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. 轻松学习JavaScript二十二:DOM编程学习之节点操作

    DOM编程不只能够查找三种节点,也能够操作节点.那就是创建,插入,删除.替换和复制节点.先来看节点 操作方法: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQ ...

  2. 编写SDR SDRAM页突发模式控制器的注意点

    网上有很多的SDR SDRAM控制器的代码,但都是基于burst1/2/4/8模式下的,这种模式下传输高速的相机数据还是有点拮据的,所以花了几天把这些模式改造成了页突发模式.我的这个控制器模型是这样的 ...

  3. Logical Operators (Transact-SQL)

    https://docs.microsoft.com/en-us/sql/t-sql/language-elements/logical-operators-transact-sql Logical ...

  4. Innosetup

    卸载的同时删除日志,卸载的时候判断程序是否正在运行,regsvr32 1.卸载程序的时候如何判断程序是否正在运行 http://bbs.csdn.net/topics/370097914 2.强制删除 ...

  5. LINQ返回DataTable类型 list转dataset 转换为JSON对象

    using System.Web.Script.Serialization; using System.Collections.Generic; using System.Reflection; us ...

  6. TP5 上传文件

    直接贴上一个完整的代码 /** * 图片上传方法 * @return [type] [description] */ /** * 1 获取到文件 * 2 验证文件的形状是不是符合上传的规则 * 3 i ...

  7. maven+spring-data-jpa环境搭建

    转自http://www.cnblogs.com/007sx/p/5658194.html 首先看一下项目结构: 所用到的jar(pom.xml): <project xmlns="h ...

  8. tab.py

    vim tab.py #!/usr/bin/env python # #Tab import sys import readline import rlcompleter import atexit ...

  9. caioj 1080 动态规划入门(非常规DP4:乘电梯)(dp数组更新其他量)

    我一开始是这么想的 注意这道题数组下标是从大到小推,不是一般的从小到大推 f[i]表示从最高层h到第i层所花的最短时间,答案为f[1] 那么显然 f[i] = f[j] + wait(j) + (j ...

  10. 中断函数中不能使用printf的原因

    vxworks 中断处理程序之所以不用printf,本质在于printf是将信息输出到标准输出设备(STDOUT)中, 整个标准输出设备是一个全局变量,由于有semTake操作,那么就会发生阻塞,vx ...