澳门蒲京网址【转】由浅入好达式树(一)创建表达式。【转】由浅入好达式树(一)创建表达式。

SQL就是通过把表达式树翻译成SQL来实现的,SQL就是通过把表达式树翻译成SQL来实现的

     
 为什么而读书表达式树?表达式树是以我们原本可以直接由代码编写的逻辑以表达式的艺术囤于树状的结构里,从而得以当运行时错过分析这个培训,然后实施,实现动态的编写和履代码。LINQ
to
SQL就是由此把表达式树翻译成SQL来兑现之,所以了解表达树有助于我们更好的解
LINQ to SQL,同时要你产生趣味,可以用她创造有无数妙趣横生的物来。

     
 为什么而上学表达式树?表达式树是以我们原来好直接由代码编写的逻辑以表达式的措施囤于树状的结构里,从而得以于运转时去分析这个培训,然后实施,实现动态的编排和实践代码。LINQ
to
SQL就是透过把表达式树翻译成SQL来兑现之,所以了解表达树有助于我们再好之敞亮
LINQ to SQL,同时要您发趣味,可以用她创造出广大有趣的事物来。

  表达式树是随着.NET
3.5出产的,所以现在吧不算什么新技巧了。但是非明白多少人口是对准它们掌握的不行透,
在上一篇Lambda表达式的回升中即扣留之出大家对Lambda表达式和表达式树要于感兴趣的,那咱们尽管来好的羁押一样圈是培训了LINQ
to SQL以及被LINQ to Everything的好东西吧。

  表达式树是随着.NET
3.5出产的,所以现在呢不算什么新技巧了。但是不知情有些人口是指向她了解的很透彻,
在上一篇Lambda表达式的复中虽看的来豪门对Lambda表达式和表达式树要比较感兴趣之,那我们虽来良的羁押同样拘留是培训了LINQ
to SQL以及被LINQ to Everything的好东西吧。

  本系列计划三首,第一首重要介绍表达式树的创立方式。第二首重要介绍表达式树的遍历问题。第三篇,将用表达式树打造一个自己之LinqProvider。

  本系列计划三首,第一首重要介绍表达式树的始建方式。第二篇重要介绍表达式树的遍历问题。第三首,将祭表达式树打造一个和谐的LinqProvider。

  • 出于浅入雅达式树(一)创建表达式树
  • 出于浅入好达式树(二)遍历表达式树
  • 出于浅入雅达式树(三)Linq to
    博客园
  • 由浅入雅达式树(一)创建表达式树
  • 由浅入雅达式树(二)遍历表达式树
  • 由浅入雅达式树(三)Linq to
    博客园

  本文主要内容:

  本文主要内容:

  • 由于Lambda表达式创建简单的表达式树
  • 手动创建复杂的表达式树
  • 表达式树类型列表及示范
  • 是因为Lambda表达式创建简单的表达式树
  • 手动创建复杂的表达式树
  • 表达式树类型列表及示范

创造一个简便的Lambda表达式树

  在
上一篇Lambda表达式着我们涉了足一直冲Lambda表达式来创造表达式树,这应是无限直白的创立表达式树的艺术了。

Expression<Func<int, int>> expr = x => x + 1;
Console.WriteLine(expr.ToString());  // x=> (x + 1)

// 下面的代码编译不通过
Expression<Func<int, int, int>> expr2 = (x, y) => { return x + y; };
Expression<Action<int>> expr3 = x => {  };

  但是变化想象的极致美好,这种艺术只能创造最简便的表达式树,复杂点的编译器就不认得了。

  右边是一个Lambda表达式,而左边是一个发表式树。为什么可以一直赋值呢?这个将要多亏我们的Expression<TDelegate>泛型类了。而Expression<TDelegate>是一直接轨自LambdaExpression的,我们来拘禁一下Expression底构造函数:

internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
    : base(typeof(TDelegate), name, body, tailCall, parameters)
{
}

  实际上这个构造函数什么呢不曾举行,只是将有关的参数传给了父类,也就是LambdaExpression,由它们将咱表达式的重头戏,名称,以及参数保存着。

Expression<Func<int, int>> expr = x => x + 1;
Console.WriteLine(expr.ToString());  // x=> (x + 1)

var lambdaExpr = expr as LambdaExpression;
Console.WriteLine(lambdaExpr.Body);   // (x + 1)
Console.WriteLine(lambdaExpr.ReturnType.ToString());  // System.Int32

foreach (var parameter in lambdaExpr.Parameters)
{
    Console.WriteLine("Name:{0}, Type:{1}, ",parameter.Name,parameter.Type.ToString());
}

//Name:x, Type:System.Int32

  澳门蒲京网址 1

  简单的来说,Expression<TDelegate>泛型类做了一如既往叠封装,方便我们根据Lambda表达式来创造Lambda表达式树。它们中产生一个更换过程,而这个转换的过程就是来在咱们编译的下。还记我们Lambda表达式中说道的么?Lambda表达式在编译之后是日常的章程,而Lambda式树是坐同样种植树的组织给加载到我们的运行时的,只有这样咱们才可以于运作时失去遍历这个培训。但是为什么咱们无能够依据Expression<TDelegate>来创造比较复杂的表达式树为?您要接着向生看。

缔造一个概括的Lambda表达式树

  在
上一篇Lambda表达式受我们提到了足以直接冲Lambda表达式来创造表达式树,这当是无与伦比直白的开创表达式树的不二法门了。

Expression<Func<int, int>> expr = x => x + 1;
Console.WriteLine(expr.ToString());  // x=> (x + 1)

// 下面的代码编译不通过
Expression<Func<int, int, int>> expr2 = (x, y) => { return x + y; };
Expression<Action<int>> expr3 = x => {  };

  但是别想象的极度美好,这种方法只能创造最简单易行的表达式树,复杂点的编译器就无识了。

  右边是一个Lambda表达式,而左边是一个发挥式树。为什么可以直接赋值呢?这个将要多亏我们的Expression<TDelegate>泛型类了。而Expression<TDelegate>是直接接轨自LambdaExpression的,我们来拘禁一下Expression的构造函数:

internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
    : base(typeof(TDelegate), name, body, tailCall, parameters)
{
}

  实际上是构造函数什么啊从不召开,只是将有关的参数传为了父类,也就算是LambdaExpression,由它将咱表达式的核心,名称,以及参数保存在。

Expression<Func<int, int>> expr = x => x + 1;
Console.WriteLine(expr.ToString());  // x=> (x + 1)

var lambdaExpr = expr as LambdaExpression;
Console.WriteLine(lambdaExpr.Body);   // (x + 1)
Console.WriteLine(lambdaExpr.ReturnType.ToString());  // System.Int32

foreach (var parameter in lambdaExpr.Parameters)
{
    Console.WriteLine("Name:{0}, Type:{1}, ",parameter.Name,parameter.Type.ToString());
}

//Name:x, Type:System.Int32

  澳门蒲京网址 2

  简单的吧,Expression<TDelegate>泛型类做了千篇一律层封装,方便我们根据Lambda表达式来创造Lambda表达式树。它们中间闹一个变换过程,而这转换的经过尽管发在咱们编译的时候。还记我们Lambda表达式中说的也?Lambda表达式在编译之后是平凡的法,而Lambda式树是因同等栽树之结构被加载到我们的周转时的,只有如此咱们才足以当运行时错过遍历这个培训。但是为什么我们无可知根据Expression<TDelegate>来创造比较复杂的表达式树啊?您要接着往生看。

始建一个错综复杂的Lambda表达式树

  下面我们即便来平等步一步之创建一个错综复杂的表达式树,你们准备好了么?上面我们叙到一直由Lambda表达式的章程来创造表达式树,可惜只有限于一种植档次。下面我们即便来演示一下哪些创造一个无参无返回值的表达式树。

// 下面的方法编译不能过 
/*
Expression<Action> lambdaExpression2 = () =>
{
    for (int i = 1; i <= 10; i++)
    {
        Console.WriteLine("Hello");
    }
};
*/     

// 创建 loop表达式体来包含我们想要执行的代码
LoopExpression loop = Expression.Loop(
    Expression.Call(
        null,
        typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
        Expression.Constant("Hello"))
        );

// 创建一个代码块表达式包含我们上面创建的loop表达式
BlockExpression block = Expression.Block(loop);

// 将我们上面的代码块表达式
Expression<Action> lambdaExpression =  Expression.Lambda<Action>(block);
lambdaExpression.Compile().Invoke();

  上面我们透过手动编码的法开创了一个无参的Action,执行了扳平组循环。代码很粗略,重要之是咱而熟悉这些各种类型的表达式以及她们之利用方式。上面我们引入了以下项目的表达式:

澳门蒲京网址 3

  看起神密的表达式树为不过这样嘛?如果大家去实施方的代码,就会见陷于死循环,我从来不啊loop加入break的尺度。为了便利大家理解,我是确实的同样步一步来什么,现在咱们即便来住之轮回。就比如面那无异截未能够编译通过的代码实现之效力雷同,我们若出口10独”Hello”。

  上面我们先勾勒了一个LoopExpression,然后把它污染为了BlockExpresson,从而形成的之同样片代码或者我们为可以说一个方法体。但是只要我们来多独执行块,而且就多单实施块里面待处理与一个参数,我们不怕得在block里面声明这些参数了。

ParameterExpression number=Expression.Parameter(typeof(int),"number");

BlockExpression myBlock = Expression.Block(
    new[] { number },
    Expression.Assign(number, Expression.Constant(2)),
    Expression.AddAssign(number, Expression.Constant(6)),
    Expression.DivideAssign(number, Expression.Constant(2)));

Expression<Func<int>> myAction = Expression.Lambda<Func<int>>(myBlock);
Console.WriteLine(myAction.Compile()());
// 4

  我们声明了一个int的变量并赋值为2,然后加上6尾声除以2。如果我们若因此变量,就必于block的公外面声明其,并且于block里面把其引入进来。否则在拖欠表达式树时会面世,变量不以企图域里的掠。

  下面我们延续我们不到位的办事,为循环进入剥离标准。为了吃大家很快的懂得loop的淡出机制,我们先行来拘禁同样截伪代码:

LabelTarget labelBreak = Expression.Label();
Expression.Loop(
    "如果 条件 成功"
        "执行成功的代码"
    "否则"
        Expression.Break(labelBreak) //跳出循环
    , labelBreak); 

  我们得靠LabelTarget
以及Expression.Break来达成退出循环的目地。下面我们来拘禁一下真真的代码:

LabelTarget labelBreak = Expression.Label();
ParameterExpression loopIndex = Expression.Parameter(typeof(int), "index");

BlockExpression block = Expression.Block(
new[] { loopIndex },
// 初始化loopIndex =1 
    Expression.Assign(loopIndex, Expression.Constant(1)),
    Expression.Loop(
        Expression.IfThenElse(
            // if 的判断逻辑
            Expression.LessThanOrEqual(loopIndex, Expression.Constant(10)),
            // 判断逻辑通过的代码
            Expression.Block(
                Expression.Call(
                    null,
                    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                    Expression.Constant("Hello")),
                Expression.PostIncrementAssign(loopIndex)),
            // 判断不通过的代码
            Expression.Break(labelBreak)
            ),labelBreak));

// 将我们上面的代码块表达式
Expression<Action> lambdaExpression =  Expression.Lambda<Action>(block);
lambdaExpression.Compile().Invoke();

  澳门蒲京网址 4

  希望地方的代码没有阻碍你学习表达式树的誓J 。

  好吧,我们以学了几个新的档次的表达式,来总一下:

澳门蒲京网址 5

  到此处,我眷恋大家应该对达式树的构建出了一个亮的认。至于为何不允我们直接冲复杂的Lambda表达式来创造表达式树也?

  • 此处的Lambda表达式实际上是一个Expression Body。
  • 此Expression Body实际上即便是咱地方讲到的Expression中之同栽。
  • 也就是说编译器需要时错开分析你究竟是啦一样栽?
  • 太简便的x=> x+1之类的吗就算是Func<TValue,TKey>
    是怪轻分析的。
  • 实则及时其间允许的Expression Body只出BinaryExpression。

澳门蒲京网址 6

  最后,我们来圆的禁闭一下.NET都为咱提供了争项目的表达式(下面这些近似都是连续自Expression)。

澳门蒲京网址 7

创办一个繁杂的Lambda表达式树

  下面我们尽管来同样步一步的创办一个繁杂的表达式树,你们准备好了么?上面我们讲到直接由Lambda表达式的办法来创造表达式树,可惜只有限于一种植档次。下面我们不怕来演示一下怎样创建一个无参无返回值的表达式树。

// 下面的方法编译不能过 
/*
Expression<Action> lambdaExpression2 = () =>
{
    for (int i = 1; i <= 10; i++)
    {
        Console.WriteLine("Hello");
    }
};
*/     

// 创建 loop表达式体来包含我们想要执行的代码
LoopExpression loop = Expression.Loop(
    Expression.Call(
        null,
        typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
        Expression.Constant("Hello"))
        );

// 创建一个代码块表达式包含我们上面创建的loop表达式
BlockExpression block = Expression.Block(loop);

// 将我们上面的代码块表达式
Expression<Action> lambdaExpression =  Expression.Lambda<Action>(block);
lambdaExpression.Compile().Invoke();

  上面我们透过手动编码的主意创造了一个无参的Action,执行了扳平组循环。代码很简短,重要的凡我们设熟悉这些各种类型的表达式以及他们的应用办法。上面我们引入了以下种类的表达式:

澳门蒲京网址 8

  看起神密的表达式树也只是这样嘛?如果大家去实践方的代码,就会沦为死循环,我从不啊loop加入break的法。为了有利于大家掌握,我是真的的均等步一步来啊,现在我们就算来歇这个轮回。就如上面那无异段不能够编译通过之代码实现之功能雷同,我们只要出口10单”Hello”。

  上面我们先行勾勒了一个LoopExpression,然后将其污染给了BlockExpresson,从而形成的之相同片代码或者我们为堪说一个方法体。但是要我们有多单执行块,而且这基本上独实施块里面要处理与一个参数,我们便得在block里面声明这些参数了。

ParameterExpression number=Expression.Parameter(typeof(int),"number");

BlockExpression myBlock = Expression.Block(
    new[] { number },
    Expression.Assign(number, Expression.Constant(2)),
    Expression.AddAssign(number, Expression.Constant(6)),
    Expression.DivideAssign(number, Expression.Constant(2)));

Expression<Func<int>> myAction = Expression.Lambda<Func<int>>(myBlock);
Console.WriteLine(myAction.Compile()());
// 4

  我们声明了一个int的变量并赋值为2,然后加上6末尾除以2。如果我们只要为此变量,就务须以block的卿外面声明其,并且于block里面将它引入进来。否则在该表达式树时会出现,变量不以图域里的擦。

  下面我们延续我们不到位的行事,为循环进入剥离标准。为了为大家迅速的理解loop的脱离机制,我们先来拘禁一样段子伪代码:

LabelTarget labelBreak = Expression.Label();
Expression.Loop(
    "如果 条件 成功"
        "执行成功的代码"
    "否则"
        Expression.Break(labelBreak) //跳出循环
    , labelBreak); 

  我们用靠LabelTarget
以及Expression.Break来达到退出循环的目地。下面我们来拘禁一下实打实的代码:

LabelTarget labelBreak = Expression.Label();
ParameterExpression loopIndex = Expression.Parameter(typeof(int), "index");

BlockExpression block = Expression.Block(
new[] { loopIndex },
// 初始化loopIndex =1 
    Expression.Assign(loopIndex, Expression.Constant(1)),
    Expression.Loop(
        Expression.IfThenElse(
            // if 的判断逻辑
            Expression.LessThanOrEqual(loopIndex, Expression.Constant(10)),
            // 判断逻辑通过的代码
            Expression.Block(
                Expression.Call(
                    null,
                    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                    Expression.Constant("Hello")),
                Expression.PostIncrementAssign(loopIndex)),
            // 判断不通过的代码
            Expression.Break(labelBreak)
            ),labelBreak));

// 将我们上面的代码块表达式
Expression<Action> lambdaExpression =  Expression.Lambda<Action>(block);
lambdaExpression.Compile().Invoke();

  澳门蒲京网址 9

  希望上面的代码没有阻止你上表达式树的狠心J 。

  好吧,我们还要套了几乎独新的路的表达式,来总一下:

澳门蒲京网址 10

  到此,我思念大家应本着发挥式树的构建有矣一个亮堂的认识。至于为何未同意我们一直冲复杂的Lambda表达式来创造表达式树为?

  • 此地的Lambda表达式实际上是一个Expression Body。
  • 这Expression Body实际上就是咱们地方讲到的Expression中之相同种植。
  • 也就是说编译器需要时刻去分析你到底是啊一样种?
  • 尽简易的x=> x+1之类的也便是Func<TValue,TKey>
    是甚爱分析的。
  • 实际上及时间允许的Expression Body只出BinaryExpression。

澳门蒲京网址 11

  最后,我们来整体的圈一下.NET还也咱提供了安路的表达式(下面这些类似都是继承自Expression)。

澳门蒲京网址 12

TypeBinaryExpression

TypeBinaryExpression typeBinaryExpression =
    Expression.TypeIs(
        Expression.Constant("spruce"),
        typeof(int));

Console.WriteLine(typeBinaryExpression.ToString());
// ("spruce" Is Int32)

TypeBinaryExpression

TypeBinaryExpression typeBinaryExpression =
    Expression.TypeIs(
        Expression.Constant("spruce"),
        typeof(int));

Console.WriteLine(typeBinaryExpression.ToString());
// ("spruce" Is Int32)

IndexExpression

ParameterExpression arrayExpr = Expression.Parameter(typeof(int[]), "Array");

ParameterExpression indexExpr = Expression.Parameter(typeof(int), "Index");

ParameterExpression valueExpr = Expression.Parameter(typeof(int), "Value");

Expression arrayAccessExpr = Expression.ArrayAccess(
    arrayExpr,
    indexExpr
);

Expression<Func<int[], int, int, int>> lambdaExpr = Expression.Lambda<Func<int[], int, int, int>>(
        Expression.Assign(arrayAccessExpr, Expression.Add(arrayAccessExpr, valueExpr)),
        arrayExpr,
        indexExpr,
        valueExpr
    );

Console.WriteLine(arrayAccessExpr.ToString());
// Array[Index]

Console.WriteLine(lambdaExpr.ToString());
// (Array, Index, Value) => (Array[Index] = (Array[Index] + Value)) 

Console.WriteLine(lambdaExpr.Compile().Invoke(new int[] { 10, 20, 30 }, 0, 5));
// 15

IndexExpression

ParameterExpression arrayExpr = Expression.Parameter(typeof(int[]), "Array");

ParameterExpression indexExpr = Expression.Parameter(typeof(int), "Index");

ParameterExpression valueExpr = Expression.Parameter(typeof(int), "Value");

Expression arrayAccessExpr = Expression.ArrayAccess(
    arrayExpr,
    indexExpr
);

Expression<Func<int[], int, int, int>> lambdaExpr = Expression.Lambda<Func<int[], int, int, int>>(
        Expression.Assign(arrayAccessExpr, Expression.Add(arrayAccessExpr, valueExpr)),
        arrayExpr,
        indexExpr,
        valueExpr
    );

Console.WriteLine(arrayAccessExpr.ToString());
// Array[Index]

Console.WriteLine(lambdaExpr.ToString());
// (Array, Index, Value) => (Array[Index] = (Array[Index] + Value)) 

Console.WriteLine(lambdaExpr.Compile().Invoke(new int[] { 10, 20, 30 }, 0, 5));
// 15

NewExpression

NewExpression newDictionaryExpression =Expression.New(typeof(Dictionary<int, string>));
Console.WriteLine(newDictionaryExpression.ToString());
// new Dictionary`2()

NewExpression

NewExpression newDictionaryExpression =Expression.New(typeof(Dictionary<int, string>));
Console.WriteLine(newDictionaryExpression.ToString());
// new Dictionary`2()

InvocationExpression

Expression<Func<int, int, bool>> largeSumTest =
    (num1, num2) => (num1 + num2) > 1000;

InvocationExpression invocationExpression= Expression.Invoke(
    largeSumTest,
    Expression.Constant(539),
    Expression.Constant(281));

Console.WriteLine(invocationExpression.ToString());
// Invoke((num1, num2) => ((num1 + num2) > 1000),539,281)

  今天咱们演示了哪些通过代码的方法去创造表达式树,然后总结了一下.NET乎我们提供的表达式类型。下一样篇,我们以持续研究发表式树的遍历问题,敬请期待,如果对表达式树起趣味的同学欢迎持续关注~,

InvocationExpression

Expression<Func<int, int, bool>> largeSumTest =
    (num1, num2) => (num1 + num2) > 1000;

InvocationExpression invocationExpression= Expression.Invoke(
    largeSumTest,
    Expression.Constant(539),
    Expression.Constant(281));

Console.WriteLine(invocationExpression.ToString());
// Invoke((num1, num2) => ((num1 + num2) > 1000),539,281)

  今天咱们演示了何等通过代码的道去创造表达式树,然后总结了一下.NET吗我们提供的表达式类型。下一样篇,我们以继承研究达式树的遍历问题,敬请期待,如果对表达式树起趣味的校友欢迎持续关注~,