LINQ Expresstion Tree 表达式树
Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation
MSDN的原文已经说明表达式树的作用就是以树状的数据结构来表示代码,树中的每个节点就是一个表达式,如方法调用或者二进制操作.表达式树的作用就是把代码以数据的形式来表达,
方便修改编辑,然后再转换为相应的代码来执行.
如何创建表达式树
我们在用委托这种类型来表示.net中的执行代码(方法) , 而做为代码的数据表示形式的表达式树我们是使用System.Linq.Expressions命名空间的Expression类型来表示.
例如委托Func<int, int>表示参数是int,返回值是int的实例方法或者静态方法的委托类型,那么Expression<Func<int, int>> 就是表示构建此类委托的数据结构,用于动态构建我们的方法.
- 直接使用lamda表达式来创建.
static void Main(string[] args) { Expression<Func<int, int>> expresstion = x => x + 5; var expressionCompiled=expresstion.Compile(); int input = 5; Console.WriteLine("input:{0},output:{1}",input, expressionCompiled(input)); Console.Read(); }
使用lamda表达式来创建表达式树有限制,就是lamda表达式只能是语句而不能是表达式块.
例如:
Expression<Func<int, int>> expresstion = x => { return x + 5; };编译器会报错:

- 使用Expression类封装好的方法来创建表达式树.
//construct the param expression var paramExpression= Expression.Parameter(typeof (int), "x"); //and then the body expression var constantExpression=Expression.Constant(5, typeof (int)); var bodyExpression= Expression.MakeBinary(ExpressionType.Add, paramExpression, constantExpression); //use the Lamda() method to construct the expression tree var func= Expression.Lambda<Func<int, int>>(bodyExpression, paramExpression).Compile(); int input = 5; Console.WriteLine("input:{0},output:{1}",input, func(5));
执行代码
表达式树只是代码的数据形式,不是执行代码,并不能直接执行.要转换为代码,需要调用Compile()方法编译,并返回委托对象.
实验一下:值对象的相等比较
DDD的值对象没有唯一的身份标识,直接来说就是没有唯一的ID(或者应该说即使ID不同的对象也可能看做是相同的对象,判断他们是否相同只能比较他们具体的一些属性,值类型不会单独存在,它应该作为实体类型或者其他值类型的属性依附存在.)
例如表示位置的值类型:
public class Position
{
/// <summary>
/// 经度
/// </summary>
[EqualKey]
public decimal Lon { get; set; }
/// <summary>
/// 纬度
/// </summary>
[EqualKey]
public decimal Lat { get; set; }
/// <summary>
/// 文字描述
/// </summary>
public string Description { get; set; }
}
我们只需要根据经度跟纬度这两个属性是否相等来判断Positon值是否相等,经度跟纬度这两个关键的属性会使用自定义的特征EqualKeyAttribute来标识.
所有的值类型都继承自类型抽象基类ValueObject,且基类的Equal方法被重写,相等比较的逻辑在虚方法中通过反射寻找每个值类型的关键属性来构建表达式树,
最后编译成特定的Func委托实现.
/// <summary>
/// 值类型基类
/// </summary>
public abstract class ValueObject<T> where T:ValueObject<T>
{
public override bool Equals(object obj)
{
if (obj == null) return false;
if (this.GetType() != obj.GetType()) return false;
return BuildValueComparer()((T)this, (T)obj);
}
/// <summary>
/// 建立值比较委托(子类可重写)
/// </summary>
/// <returns></returns>
protected virtual Func<T, T, bool> BuildValueComparer()
{
return ValueObjectComparerFactory.BuildComparer<T>();
}
/// <summary>
/// 重载==
/// </summary>
/// <returns></returns>
public static bool operator ==(ValueObject<T> source,ValueObject<T> compare)
{
if (source == null)
{
return compare == null;
}
return source.Equals(compare);
}
/// <summary>
/// 重载!=
/// </summary>
/// <returns></returns>
public static bool operator !=(ValueObject<T> source, ValueObject<T> compare)
{
return !(source == compare);
}
}
[AttributeUsage(AttributeTargets.Property)]
public class EqualKeyAttribute : Attribute
{
}
internal interface IValueObjectComparerBuilder<T>
{
Func<T, T, bool> BuildComparer<T>();
}
static class ValueObjectComparerFactory
{
private static Dictionary<Type, object> cache = new Dictionary<Type, object>();
private static object syncObject = new object();
internal static Func<T, T, bool> BuildComparer<T>()
{
var objectType = typeof (T);
if (!cache.ContainsKey(objectType))
{
lock (syncObject)
{
if (!cache.ContainsKey(objectType))
{
IValueObjectComparerBuilder<T> builder = new ExpressionTreeComparerBuilder<T>();
cache.Add(objectType, builder.BuildComparer<T>());
}
}
}
return cache[objectType] as Func<T, T, bool>;
}
}
internal class ExpressionTreeComparerBuilder <T>: IValueObjectComparerBuilder<T>
{
public Func<T, T, bool> BuildComparer<T>()
{
Expression<Func<T, T, bool>> expression = null;
Expression finalExpression = null;
Type objectType = typeof (T);
//parameter a,b
var paramA = Expression.Parameter(objectType, "a");
var paramB = Expression.Parameter(objectType, "b");
//var typeParamA = Expression.Convert(paramA, objectType);
//var typeParamB = Expression.Convert(paramB, objectType);
foreach (var propertyInfo in objectType.GetProperties())
{
if (propertyInfo.GetCustomAttribute<EqualKeyAttribute>(false) != null)
{
var propertyExpressionA = Expression.Property(paramA, propertyInfo);
var propertyExpressionB = Expression.Property(paramB, propertyInfo);
var equalExpression = Expression.MakeBinary(ExpressionType.Equal, propertyExpressionA, propertyExpressionB);
if (finalExpression == null)
finalExpression = equalExpression;
else
finalExpression = Expression.MakeBinary(ExpressionType.AndAlso, finalExpression, equalExpression);
}
}
if (finalExpression != null)
return Expression.Lambda<Func<T, T, bool>>(finalExpression, paramA, paramB).Compile();
else
return (a, b) => a.Equals(b);
}
}
测试一下:
static void Main(string[] args)
{
Position pos1 = new Position
{
Lat = 100,
Lon = 100,
Description = "佛山市"
};
Position pos2 = new Position
{
Lat = 100,
Lon = 100,
Description = "顺德区"
};
Position pos3 = new Position
{
Lat = 111,
Lon = 111,
Description = "佛山市"
};
Console.WriteLine("{0}=={1} Result=>{2}",pos1.ToString(),pos2.ToString(), pos1.Equals(pos2).ToString());
Console.WriteLine("{0}=={1} Result=>{2}", pos1.ToString(), pos3.ToString(), pos1.Equals(pos3).ToString());
Console.Read();

To be continued………………
参考:
https://blogs.msdn.microsoft.com/charlie/2008/01/31/expression-tree-basics/
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/index
LINQ Expresstion Tree 表达式树的更多相关文章
- Linq系列(7)——表达式树之ExpressionVisitor
大家好,由于今天项目升级,大家都在获最新代码,所以我又有时间在这里写点东西,跟大家分享. 在上一篇的文章中我介绍了一个dll,使大家在debug的时候可以可视化的看到ExpressionTree的Bo ...
- Linq系列(5)——表达式树之案例应用
在进入今天的正题之前,先感慨下本人的blog的人气一篇不如一篇.再加上换公司后人身自由受到了比之前大得多得多的限制,实在令本人有些郁闷.不过每次提笔写些东西跟大家分享,总是能让我感到愉悦和欣慰,希望我 ...
- C# - LINQ 表达式树
表达式树(Expression Tree) 表达式树是不可执行的代码,它只是用于表示一种树状的数据结构,树上的每一个节点都表示为某种表达式类型,大概有25种表达式类型,它们都派生自Expression ...
- 表达式树(Expression Tree)
你每创建一个表示表达式的实例时,都可以将该类型实例看成是一棵表达式树.每种表示表达式的类型都有一个具体的类型,如Expression的Variable()方法创建的是ParameterExpressi ...
- 追根溯源之Linq与表达式树
一.什么是表达式树? 首先来看下官方定义(以下摘录自巨硬官方文档) 表达式树表示树状数据结构中的代码,其中每个节点都是表达式,例如,方法调用或诸如的二进制操作x < y. 您可以编译 ...
- [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门
[.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...
- 转载:C#特性-表达式树
原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...
- C#特性-表达式树
表达式树ExpressionTree 表达式树基础 转载需注明出处:http://www.cnblogs.com/tianfan/ 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希 ...
- C#编程(六十六)----------表达式树总结
表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代码之前修改或转换此代码,那么它是很有用的.有其是当你要将C#代码----如LINQ查询表达式转换成其他代码在另一个程 ...
随机推荐
- 请为CMyString类型编写构造函数、copy构造函数、析构函数和赋值运算符函数。
如下为类型CMyString的声明,请为该类型编写构造函数.copy构造函数.析构函数和赋值运算符函数. class CMyString { public: CMyString(const char* ...
- go_micro相关书签
https://micro.mu/docs/cn/index.html gomicro文档 https://github.com/micro/go-micro gomicro代码 windows安装 ...
- JavaScrpt常用的封装方法
1.闭包封装.在这个封装方法中,所有的实例成员都共享属性和方法, 使得所有得方法和属性都私有且对象间共享 (function ($) { var Person = function(name) { r ...
- jieba库的使用和好玩的词云
1.jieba库基本介绍 (1).jieba库概述 jieba是优秀的中文分词第三方库 - 中文文本需要通过分词获得单个的词语 - jieba是优秀的中文分词第三方库,需要额外安装 - ...
- Python实现:汉诺塔问题
汉诺塔问题不管在任何编程语言里都是经典问题,是采用递归算法的经典案例,该问题可以抽象如下: 一 .3根圆柱A,B,C,其中A上面串了n个圆盘 二 .这些圆盘从上到下是按从小到大顺序排列的,大的圆盘任何 ...
- go安装和开发工具安装
go适合做什么 l 服务端开发 l 分布式系统 l 网络编程 l 区块链开发 l 内存KV数据库,例如boltDB.levelDB l 云平台 一 go安装 官网:https://golang.goo ...
- java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context 错误
spring boot 项目启动报错:原因一般是注入了相同名字的service -- :: com.gxcards.mes.MainWwwWeb: logStartupProfileInfo INFO ...
- 转载aaa
前言 对于喜欢逛CSDN的人来说,看别人的博客确实能够对自己有不小的提高,有时候看到特别好的博客想转载下载,但是不能一个字一个字的敲了,这时候我们就想快速转载别人的博客,把别人的博客移到自己的空间 ...
- PDOMySQL实现类, 自动重置无效连接
PHP连接MySQL时, 有可能因为MySQL的原因,而使得php里生成的连接无效.比如超过8小时, MySQL自动断开空闲连接的问题,虽然可以调高这个时间,但显然这不是比较文艺的实现方式.现在洒家用 ...
- javascript高级程序设计第3版——第4章 变量作用域以及内存