帶你一文了解C#中的Expression
前言
我們書接上文,我們?cè)?a href="http://www.dbjr.com.cn/article/231764.htm" target="_blank">了解LINQ下面有說(shuō)到在本地查詢IEnumerbale主要是用委托來(lái)作為傳參,而解析型查詢
IQueryable則用Expression來(lái)作為傳參:
public static IEnumerable<T> Where<T>(this IEnumerable<T> enumable, Func<T, bool> func) public static IQueryable<T> Where<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> func)
那么我們就來(lái)聊聊有關(guān)表達(dá)式Expression里面的東西吧
Expression與Expression Tree
首先我們來(lái)寫下一些代碼:
Expression<Func<int, int>> expression = (num) => num + 5; Console.WriteLine($"NodeType:{expression.NodeType}"); Console.WriteLine($"Body:{expression.Body}"); Console.WriteLine($"Body Type: {expression.Body.GetType()}"); Console.WriteLine($"Body NodeType: {expression.Body.NodeType}");
輸出如下:
NodeType:Lambda
Body:(num + 5)
Body Type: System.Linq.Expressions.SimpleBinaryExpression
Body NodeType: Add
我們將expression轉(zhuǎn)為L(zhǎng)ambdaExpression看看都有啥:
if (expression.NodeType == ExpressionType.Lambda) { var lambda = (LambdaExpression)expression; var parameter = lambda.Parameters.Single(); Console.WriteLine($"parameter.Name:{parameter.Name}"); Console.WriteLine($"parameter.Type:{parameter.Type}"); Console.WriteLine($"parameter.ReturnType:{lambda.ReturnType}"); }
輸出如下:
parameter.Name:num
parameter.Type:System.Int32
parameter.ReturnType:System.Int32
由于我們知道expression.Body是BinaryExpression,那么我們就將其轉(zhuǎn)為它,然后我們繼續(xù)看下去:
if (expression.Body.NodeType == ExpressionType.Add) { var binaryExpreesion = (BinaryExpression)expression.Body; Console.WriteLine($"Left Type:{binaryExpreesion.Left.GetType()}"); Console.WriteLine($"Left NodeType:{binaryExpreesion.Left.NodeType}"); Console.WriteLine($"Right Type:{binaryExpreesion.Right.GetType()}"); Console.WriteLine($"Right NodeType:{binaryExpreesion.Right.NodeType}"); if (binaryExpreesion.Left is ParameterExpression parameterExpreesion) { Console.WriteLine($"parameterExpreesion.Name:{parameterExpreesion.Name}"); Console.WriteLine($"parameterExpreesion.Type:{parameterExpreesion.Type}"); } if (binaryExpreesion.Right is ConstantExpression constantExpreesion) { Console.WriteLine($"constantExpreesion.Value:{constantExpreesion.Value}" ); } }
輸出如下:
Left Type:System.Linq.Expressions.PrimitiveParameterExpression`1[System.Int32]
Left NodeType:Parameter
Right Type:System.Linq.Expressions.ConstantExpression
Right NodeType:Constant
parameterExpreesion.Name:num
parameterExpreesion.Type:System.Int32
constantExpreesion.Value:5
最后我們將表達(dá)式樹(shù)轉(zhuǎn)為委托:
var @delegate = expression.Compile(); Console.WriteLine(@delegate?.Invoke(2));
輸出:
7 //2+5
實(shí)際上,通過(guò)Expression<Func<int, int>> expression = (num) => num + 5;,賦值后的expression 變成了一個(gè)表達(dá)式樹(shù),它的結(jié)構(gòu)是這樣的:
而有意思的是二元表達(dá)式樹(shù)BinaryExpression是一個(gè)二叉樹(shù),而LambdaExpression則是一個(gè)支持參數(shù)的表達(dá)式,能夠通過(guò)其Parameters屬性知道傳入的參數(shù)的類型和數(shù)量,通過(guò)ReturnType知道返回值是什么類型
而我們?cè)倏纯凑麄€(gè)關(guān)于Expression的繼承關(guān)系鏈:
因此,我們也可以顯式的通過(guò)各自Expreesion的實(shí)現(xiàn)子類來(lái)創(chuàng)建跟lambda表達(dá)式一樣的結(jié)果:
var parameterExpreesion1 = Expression.Parameter(typeof(int), "num"); BinaryExpression binaryExpression1 = Expression.MakeBinary(ExpressionType.Add, parameterExpreesion1, Expression.Constant(5)); Expression<Func<int, int>> expression1 = Expression.Lambda<Func<int, int>>(binaryExpression1, parameterExpreesion1); if (expression1.Body.NodeType == ExpressionType.Add) { var binaryExpreesion1 = (BinaryExpression)expression1.Body; Console.WriteLine($"Left Type:{binaryExpreesion1.Left.GetType()}"); Console.WriteLine($"Left NodeType:{binaryExpreesion1.Left.NodeType}"); Console.WriteLine($"Right Type:{binaryExpreesion1.Right.GetType()}"); Console.WriteLine($"Right NodeType:{binaryExpreesion1.Right.NodeType}"); if (binaryExpreesion1.Left is ParameterExpression parameterExpreesion2) { Console.WriteLine($"parameterExpreesion.Name:{parameterExpreesion2.Name}"); Console.WriteLine($"parameterExpreesion.Type:{parameterExpreesion2.Type}"); } if (binaryExpreesion1.Right is ConstantExpression constantExpreesion1) { Console.WriteLine($"constantExpreesion.Value:{constantExpreesion1.Value}"); } var @delegate1 = expression1.Compile(); Console.WriteLine(@delegate1(2));
輸出結(jié)果:
Left Type:System.Linq.Expressions.PrimitiveParameterExpression`1[System.Int32]
Left NodeType:Parameter
Right Type:System.Linq.Expressions.ConstantExpression
Right NodeType:Constant
parameterExpreesion.Name:num
parameterExpreesion.Type:System.Int32
constantExpreesion.Value:5
result:7
我們則發(fā)現(xiàn),結(jié)果是一模一樣的,但是費(fèi)勁了很多,因此用lamda構(gòu)建表達(dá)式樹(shù)是一個(gè)非常愉快的語(yǔ)法糖,讓你能夠愉快的在使用表達(dá)式和表達(dá)式樹(shù)
參考
- 《C#7.0核心技術(shù)指南》
源碼
BlogCodeSample/ExpressionSample at main · ZhengDaoWang/BlogCodeSample
總結(jié)
到此這篇關(guān)于C#中Expression的文章就介紹到這了,更多相關(guān)C#的Expression內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#編程實(shí)現(xiàn)發(fā)送郵件的方法(可添加附件)
這篇文章主要介紹了C#編程實(shí)現(xiàn)發(fā)送郵件的方法,具備添加附件的功能,涉及C#文件傳輸及郵件發(fā)送的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11使用C# CefSharp Python采集某網(wǎng)站簡(jiǎn)歷并且自動(dòng)發(fā)送邀請(qǐng)短信的方法
這篇文章主要給大家介紹了關(guān)于如何使用C# CefSharp Python采集某網(wǎng)站簡(jiǎn)歷并且自動(dòng)發(fā)送邀請(qǐng)短信的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧2019-03-03C#實(shí)現(xiàn)控制電腦注銷,關(guān)機(jī)和重啟
這篇文章主要為大家介紹了C#如何實(shí)現(xiàn)控制電腦注銷,關(guān)機(jī)和重啟功能,本案例涉及的知識(shí)點(diǎn)包含:Process、Shell32.dll、User32.dll、Struct數(shù)據(jù)結(jié)構(gòu),感興趣的可以了解一下2022-09-09通過(guò)C#實(shí)現(xiàn)自動(dòng)售貨機(jī)接口
這篇文章主要介紹了通過(guò)C#實(shí)現(xiàn)自動(dòng)售貨機(jī)接口,需要的朋友可以參考下2015-07-07C#的String轉(zhuǎn)換成float防止精度丟失問(wèn)題的解決
這篇文章主要介紹了C#的String轉(zhuǎn)換成float防止精度丟失問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Unity實(shí)現(xiàn)鼠標(biāo)點(diǎn)2D轉(zhuǎn)3D進(jìn)行旋轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)鼠標(biāo)點(diǎn)2D轉(zhuǎn)3D進(jìn)行旋轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04c#實(shí)現(xiàn)簡(jiǎn)單控制臺(tái)udp異步通信程序示例
這篇文章主要介紹了c#實(shí)現(xiàn)簡(jiǎn)單控制臺(tái)udp異步通信程序示例,需要的朋友可以參考下2014-04-04