.net 系列:Expression表達式樹、lambda、匿名委托 的使用

来源:http://www.cnblogs.com/nicholashjh/archive/2017/11/30/7928205.html
-Advertisement-
Play Games

首先定義一個泛型委托類型,如下: 實現泛型委托的主體代碼,並調用: 以上代碼展示了委托類型Function<T>主體定義的四種方式,分別是實名委托、匿名委托、Lambda表達式、expression表達式樹。 從Function<T>委托主體的代碼定義來看是越來越簡單和友好,這些變化很大部分應歸功於 ...


首先定義一個泛型委托類型,如下:

public delegate T Function<T>(T a, T b);

實現泛型委托的主體代碼,並調用:

 

 

 1 public static string Add(string a, string b)
 2           {
 3                 return string.Format("{0} #### {1}",a,b);
 4           }
 5  //實名委托方式
 6  Function<string> func = new Function<string>(Add);
 7  Console.WriteLine( func("hello", "world") );
 8 
 9  //匿名委托方式
10  Function<string> func1 = new Function<string>(delegate(string a, string b) {
11         return string.Format("{0} @@@@ {1}",a,b);
12  });
13  Console.WriteLine(func1("hello", "world"));
14 
15  //Lambda表達式方式
16  Function<string> func2 = (a, b) => string.Format("{0} **** {1}", a, b);
17  Console.WriteLine(func2("hello", "world"));
18 
19  Expression<Function<string>> func2_0;
20  //func2_0 = func;  //不支持將委托直接賦值給表達式樹
21  //func2_0 = func1; //不支持將委托直接賦值給表達式樹
22  //func2_0 = func2; //不支持將委托直接賦值給表達式樹
23 
24  //(a, b) => string.Format("{0} **** {1}", a, b)語句塊的類型是lambda expression,即我們常說的lambda表達式
25  //所以,func2_0 = (a, b) => string.Format("{0} **** {1}", a, b)的直接賦值是沒有問題的。
26  func2_0 = (a, b) => string.Format("{0} **** {1}", a, b);
27  Console.WriteLine(func2_0.Compile()("hello", "world"));

 

以上代碼展示了委托類型Function<T>主體定義的四種方式,分別是實名委托、匿名委托、Lambda表達式、expression表達式樹。

從Function<T>委托主體的代碼定義來看是越來越簡單和友好,這些變化很大部分應歸功於C#的語法糖。

總結:不管委托主體在編寫的形式上怎麼簡化,但依然改變不了它委托類型的本質,當委托代碼塊被調用時會即時執行。

隨著C#的發展,後來加入了expression這個東東,簡稱表達式樹,我想用過ling to sql、linq to entity、linq to xml等等的你是不會陌生的。
expression是一種數據結構,我們可以將平常編寫的C#語句塊(或者叫表達式)的各部分進行分解並存入這個樹結構當中,保存在expression樹結構中的語句塊是不能直接執行的。
當我們需要將expression結構中的數據抽取並還原時就需要調用expression.Compile()方法,這裡我稱之為編譯。編譯後得到的結果就是我們之前存入的語句塊,這是數據結構還原成語句塊的過程(這是一個比喻)。
當然將數據還原成語句塊時依據解析引擎的不同會產生不同的輸出結果,如果引擎是linq to sql那麼解析後輸出的就是可供資料庫執行的sql,如果引擎是linq to xml則解析後輸出的是Xpath之類的表達式(沒親自驗證)

下麵就請你和我一起來體驗一下expression表達式數據的存儲和編譯輸出吧!!!!仍以上面的場景為例子

 1 //expression表達式樹主體構造開始
 2 ParameterExpression paramA = Expression.Parameter(typeof(object), "a"); //聲明Lambda表達式中的參數表達式a
 3 ParameterExpression paramB = Expression.Parameter(typeof(object), "b"); //聲明Lambda表達式中的參數表達式b
 4 ConstantExpression constantExp = Expression.Constant("{0} !!!!! {1}",typeof(string));//聲明文本塊常量表達式
 5 MethodCallExpression bodyExp = Expression.Call(typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object), typeof(object) })
 6                 , new Expression[] { constantExp, paramA, paramB }); //聲明String.Format()方法調用表達式
 7 //expression表達式樹主體構造結束
 8 
 9 
10 //1.構造類型為LambdaExpression的lambda表達式樹,編譯後得到委托的基元類型(弱類型)。
11 LambdaExpression func3 = Expression.Lambda(bodyExp, paramA, paramB);//將以上各個表達式部分組合為Lambda表達式
12 Delegate dg = func3.Compile();//編譯表達式樹得到委托
13 Console.WriteLine(dg.DynamicInvoke("hello", "world"));//調用委托並將結果輸出到控制台
14 //Console.WriteLine(func3.Compile().DynamicInvoke("hello", "world")); //上面兩步可以簡化為這句代碼
15 
16 //2.構造類型為Expression<Function<string>>的泛型lambda表達式樹,編譯後得到委托可直接調用。
17 Expression<Function<string>> func4 = Expression.Lambda<Function<string>>(bodyExp, paramA, paramB);
18 Console.WriteLine(func4.Compile()("xxxx", "yyyy"));
19 
20  //3.構造類型為Expression<Func<string, string, string>>的泛型lambda表達式樹,編譯後得到委托可直接調用。
21  //與上面的區別是這裡用系統定義的Func<in T1, in T2, out TResult>泛型委托代替了自定義的Function<T>委托。
22  Expression<Func<string, string, string>> func5 = Expression.Lambda<Func<string, string, string>>(bodyExp, paramA, paramB);
23  Console.WriteLine(func5.Compile()("yyyy", "zzzz"));
24 
25  //以上總結了expression表達式的創建和調用的不同方式,以下是幾個有關expression的擴展例子
26  //4.動態構造string.Concat("hello", "world")語句塊
27  var concatMethod = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) });
28  var addExpr = Expression.Add(Expression.Constant("hello "), Expression.Constant("world"), concatMethod);
29  Expression<Func<string>> e = Expression.Lambda<Func<string>>(addExpr);
30  Console.WriteLine(e.Compile()());
31 
32  //5.動態構造Math.Sin(100)語句塊
33  ParameterExpression expA = Expression.Parameter(typeof(double), "a"); //參數a
34  MethodCallExpression expCall = Expression.Call(
35         typeof(Math).GetMethod("Sin",new Type[]{typeof(double)}),expA); 
36  LambdaExpression exp = Expression.Lambda(expCall, expA); // a => Math.Sin(a)
37  Console.WriteLine( exp.Compile().DynamicInvoke(100) );
38 
39  //6.動態構造Console.WriteLine("aaa")語句塊
40  ConstantExpression _constExp = Expression.Constant("aaa", typeof(string));//一個常量
41  MethodCallExpression _methodCallexp = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), _constExp);
42  Expression<Action> consoleLambdaExp = Expression.Lambda<Action>(_methodCallexp);
43  consoleLambdaExp.Compile()();

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 整數回覆 整數回覆就是一個以 ":" 開頭, CRLF 結尾的字元串表示的整數。 比如說, ":0\r\n" 和 ":1000\r\n" 都是整數回覆。 返回整數回覆的其中兩個命令是 INCR 和 LASTSAVE 。 被返回的整數沒有什麼特殊的含義, INCR 返回鍵的一個自增後的整數值, 而 L ...
  • 直接計算字元串算式方法: ...
  • 射線:從一個點往一個方向,發射一根無限長的射線,這根射線會與場景中帶有 Collider 組件的物體發生碰撞。 射線的使用: 根據上面的代碼: hitInfo.point:表示碰撞點的坐標。 Physics.Raycast():使用這個方法檢測射線時,因為該方法重載很多,一定要弄清楚自己使用的是哪個 ...
  • 實現代碼(C#) 1、發送GET指令 2、接收批量回覆 3、 結果: 代碼重構 1、發送指令 2、接收回覆 3、GET和SET指令 4、重構後的代碼 是不是簡潔很多??? 5、結果 ...
  • 結論: 1、EF 查詢 比ADO慢,甚至直接報告超時錯誤,原因不詳。 2、在原生ADO.Net中 使用 參數化查詢 比 直接使用sql拼接 慢幾十倍!!! ADO.Net代碼測試 EF代碼(已捨棄) 資料庫內部測試 sqlHelper類 博客園非常蛋疼的說:字數少有150字不能發佈的首頁。 答:親, ...
  • using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.Diagnostics; using System.IO; using System.Threading; using Sys... ...
  • 文檔中包含圖片的話,會使得整個文檔比較大,占用存儲空間且不利於快速、高效的傳輸文件。針對一些包含大量高質圖片的PDF文檔,若是對圖片進行壓縮,可以有效減少文檔的占用空間。並且,在文檔傳輸過程中也可以減少傳送時間,提高效率。本文將介紹2種通過C#來實現PDF圖片文檔壓縮的方法。使用此方法,需要用到最新 ...
  • 相關下載:https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki 在Visual Studio中要支持訪問SQLite文件數據源,首先需要安裝SQLite .NET的相關組件,安裝完SQLite組件後,就可以在Vi ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...