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>> 就是表示构建此类委托的数据结构,用于动态构建我们的方法.

  1. 直接使用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; };

    编译器会报错:

  2. 使用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 表达式树的更多相关文章

  1. Linq系列(7)——表达式树之ExpressionVisitor

    大家好,由于今天项目升级,大家都在获最新代码,所以我又有时间在这里写点东西,跟大家分享. 在上一篇的文章中我介绍了一个dll,使大家在debug的时候可以可视化的看到ExpressionTree的Bo ...

  2. Linq系列(5)——表达式树之案例应用

    在进入今天的正题之前,先感慨下本人的blog的人气一篇不如一篇.再加上换公司后人身自由受到了比之前大得多得多的限制,实在令本人有些郁闷.不过每次提笔写些东西跟大家分享,总是能让我感到愉悦和欣慰,希望我 ...

  3. C# - LINQ 表达式树

    表达式树(Expression Tree) 表达式树是不可执行的代码,它只是用于表示一种树状的数据结构,树上的每一个节点都表示为某种表达式类型,大概有25种表达式类型,它们都派生自Expression ...

  4. 表达式树(Expression Tree)

    你每创建一个表示表达式的实例时,都可以将该类型实例看成是一棵表达式树.每种表示表达式的类型都有一个具体的类型,如Expression的Variable()方法创建的是ParameterExpressi ...

  5. 追根溯源之Linq与表达式树

    一.什么是表达式树?   首先来看下官方定义(以下摘录自巨硬官方文档)   表达式树表示树状数据结构中的代码,其中每个节点都是表达式,例如,方法调用或诸如的二进制操作x < y.   您可以编译 ...

  6. [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门

    [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...

  7. 转载:C#特性-表达式树

    原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...

  8. C#特性-表达式树

    表达式树ExpressionTree   表达式树基础 转载需注明出处:http://www.cnblogs.com/tianfan/ 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希 ...

  9. C#编程(六十六)----------表达式树总结

    表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代码之前修改或转换此代码,那么它是很有用的.有其是当你要将C#代码----如LINQ查询表达式转换成其他代码在另一个程 ...

随机推荐

  1. mysql workbench快捷键小结

    执行整篇sql脚本, ctrl+shift+enter 执行当前行,ctrl+enter 注释/取消注释, ctrl+/   [注意]这里的 / 指的是小键盘中的除法Divide符号格式化sql语句( ...

  2. Class.jsp

    <%@page import="java.util.Random"%> <%@ page language="java" contentTyp ...

  3. postgres 11 单实例最大支持多少个database?

    有人在pg8时代(10年前)问过,当时说10000个没问题,而且每个db会在/base下建立1个文件夹, 文件ext3只支持32000个子文件夹,所以这是上限了. 而现在早就ext4了,根本没有限制了 ...

  4. MySQL 存储过程循环

    MySQL  存储过程循环 MySQL循环语句(包括WHILE,REPEAT和LOOP)来根据条件反复运行代码块. MySQL提供循环语句,允许您根据条件重复执行一个SQL代码块. MySQL中有三个 ...

  5. @RequestMapping的Ant风格URL

    Ant风格资源地址支持3中匹配符 ? 匹配文件名中一个字符. *   匹配 文件名中任意字符 **  匹配多层路径 例如 /hello/*/myspring 匹配 /hello/abc/mysprin ...

  6. hsy单词

    题意:略 在ac自动机上,一个节点出现的次数等于能通过fail到它的节点的次数之和.而叶节点就等于它被爬过的次数. #include <iostream> #include <cst ...

  7. Python+turtle交互式绘图:可以用鼠标拖动的小海龟

    下面是我画海龟的过程: (1)打开python: 2.调用turtle库,先设置一些基础设置,与一个画龟的函数 from turtle import Screen,Turtle,mainloop cl ...

  8. Appium + Python环境搭建(移动端自动化)

    安装JDK,配置JDK环境    百度搜索下载就行,这里分享一个下载链接:https://pan.baidu.com/s/1snuTOAx 密码:9z8r. 下载好后点击进行安装.安装好后进行环境变量 ...

  9. 浅谈UML中常用的几种图——用例图

    1.UML简介 统一建模语言(Unified Modeling Language,UML)又称标准建模语言,是始于1997年的一个OMG标准,它是一个支持模型化和软件系统开发的图形化语言,为软件开发的 ...

  10. Matlab:正则Euler分裂

    函数文件1: function b=F(x0,h,u,tau) b(,)=x0()-u(); b(,)=x0()-u()+*h*1e8*cos(tau)*x0(); 函数文件2: function g ...