C# 表達式樹講解(一)

1、前言

一直想寫一篇Dpper的定製化擴展的文章,可是裏面會設計到對Lambda表達式的解析,而解析Lambda表達式,就必需要知道表達式樹的相關知識點。我但願能經過對各個模塊的知識點或者運用可以多一點的講解,可以幫助到園友瞭解得更多。雖然講解得不全面,若是能成爲打開這塊的一把鑰匙,也是蝸牛比較欣慰的。html

表達式系列目錄express

C# 表達式樹講解(一)api

C# 表達式樹遍歷(二)數據結構

C# 表達式樹分頁擴展(三)ide

C# 表達式樹Lambda擴展(四)函數

2、表達樹理解

表達式樹以樹形數據結構表示代碼,其中每個節點都是一種表達式,它將咱們原來能夠直接由代碼編寫的邏輯以表達式的方式存儲在樹狀的結構裏,從而能夠在運行時去解析這個樹,而後執行,實現動態的編輯和執行代碼。在.Net 裏面的Linq to SQL就是對錶達式樹的解析。spa

這裏先講解下表達式和表達式樹,表達式相信你們都知道,好比x+5或者5,均可以算是表達式,而表達式樹裏面的樹指的二叉樹,也就是表達式的集合,C#中的Expression類就是表達式類。對於一棵表達式樹,其葉子節點都是參數或者常數,非葉子節點都是運算符或者控制符。設計

2.一、表達式的建立

Lambda表達式方法:3d

Expression<Func<int, int,bool>> fun = (x, y) => x < y

這種方法建立出的表達式根節點類型爲ExpressionType.Lambda,Type類型爲返回值類型typeof(bool)code

組裝法(經過 API 建立表達式樹):

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

咱們先建立了兩個參數表達式num和5,而後用LessThan組裝在一塊兒,最終的表達式爲「num<5」,expr的節點類型爲LessThan,Type類型爲typeof(bool)

咱們先看看錶達式樹裏面的構造

首先Expression<TDelegate>的功能是將強類型Lambda表達式表示爲表達式樹形式的數據結構,他的父類是LambdaExpression,比較他們代碼可知,Lambda表達式的主體,名稱和參數所有保存在LambdaExpression裏面。

Expression<TDelegate>與LambdaExpression代碼截圖:

image

image

LambdaExpression裏面的Body就是咱們的表達式。

C#表達式給咱們提供了豐富的表達式類,進入到LambdaExpression類裏面

image

方法返回類型以「Expression」結尾的,基本上都是一個表達式類。

每一個表達式表明的定義和建立方法,能夠參照微軟官方文檔https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.binaryexpression?view=netframework-4.8

下面是日常使用最多的表達式

ConstantExpression:常量表達式

ParameterExpression:參數表達式

UnaryExpression:一元運算符表達式

BinaryExpression:二元運算符表達式

TypeBinaryExpression:is運算符表達式

ConditionalExpression:條件表達式

MemberExpression:訪問字段或屬性表達式

MethodCallExpression:調用成員函數表達式

Expression<TDelegate>:委託表達式

2.二、表達式的解析

表達式樹解析

經過LambdaExpression類咱們能夠知道,表達式樹包含:參數[Parameters],表達式樹類型[NodeType],表達式[Body],返回類型[ReturnType],Lambda表達式的委託[Compile]以及Lambda表達式名稱[name],如圖所示:

image

表達式解析:

全部的表達式都包含:左節點【Left】,右節點【Right】,類型【NodeType】,不一樣的表達式還會有其餘屬性,這裏的左右節點依舊是表達式。

下圖是BinaryExpression表達式截圖

image

表達式樹和表達式裏面的類型NodeType是一個枚舉,一共有85個類型,有興趣的朋友能夠去了解下。

經常使用的類型以下:

ExpressionType.And:C#中相似於&

ExpressionType.AndAlso:C#中相似於&&

ExpressionType.Or:C#中相似於|

ExpressionType.OrElse:C#中相似於||

ExpressionType.Equal:C#中相似於==

ExpressionType.NotEqual:C#中相似於!=

ExpressionType.GreaterThan:C#中相似於>

ExpressionType.GreaterThanOrEqual:C#中相似於>=

ExpressionType.LessThan:C#中相似於<

ExpressionType.LessThanOrEqual:C#中相似於<=

ExpressionType.Add:C#中相似於+

ExpressionType.AddChecked:C#中相似於+

ExpressionType.Subtract:C#中相似於-

ExpressionType.SubtractChecked:C#中相似於-

ExpressionType.Divide:C#中相似於/

ExpressionType.Multiply:C#中相似於*

ExpressionType.MultiplyChecked:C#中相似於*

2.三、編譯表達式樹

在表達式建立那,咱們組合建立了一個Lambda表達式,那麼應該怎麼使用它呢?在「表達式的解析」裏面,LambdaExpression類和Expression<TDelegate>類都有一個Compile的方法,學名是Lambda表達式的委託,其實就是Lambda表達式編譯函數的委託,因此咱們只須要調用他,獲得的結果就是一個函數方法。

代碼修改以下:

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

Console.WriteLine($"Lambda的內容:{lambda1.ToString()}");

//表達式的編譯
var func = lambda1.Compile();
Console.WriteLine($"Lambda的運行結果:{func(6)}");

運行結果

image

3、總結

這裏咱們對錶達式作了基本的講解,相信你們對Lambda表達式有了初步的瞭解,下面咱們將繼續講解對一個表達式樹的遍歷。

相關文章
相關標籤/搜索