[C#] 說說表達式樹 - Expression Trees(更新於09/16)

来源:http://www.cnblogs.com/liqingwen/archive/2016/09/16/5868688.html
-Advertisement-
Play Games

說說表達式樹 - Expression Trees 序 簡單說下表達式樹。 目錄 簡介 根據 Lambda 表達式創建表達式樹 通過 API 創建表達式樹 解析表達式樹 表達式樹永久性 編譯表達式樹 執行表達式樹 修改表達式樹 調試 簡介 表達式樹以樹形數據結構表示代碼,其中每一個節點都是一種表達式 ...


說說表達式樹 - Expression Trees

  簡單說下表達式樹。

 

目錄

 

簡介

  表達式樹以樹形數據結構表示代碼,其中每一個節點都是一種表達式,比如方法調用和 x < y 這樣的二元運算等。

  你可以對錶達式樹中的代碼進行編輯和運算。這樣能夠動態修改可執行代碼、在不同資料庫中執行 LINQ 查詢以及創建動態查詢。 

  表達式樹還能用於動態語言運行時 (DLR) 以提供動態語言和 .NET Framework 之間的互操作性,同時保證編譯器編寫員能夠發射表達式樹而非 Microsoft 中間語言 (MSIL)。 

 

一、根據 Lambda 表達式創建表達式樹

  若 lambda 表達式被分配給 Expression<TDelegate> 類型的變數,則編譯器可以發射代碼以創建表示該 lambda 表達式的表達式樹。  

  C# 編譯器只能從表達式 lambda (或單行 lambda)生成表達式樹。 

  下列代碼示例使用關鍵字 Expression創建表示 lambda 表達式:

1             Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
2             Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
3             Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;

 

二、通過 API 創建表達式樹

  通過 API 創建表達式樹需要使用 Expression 類

  下列代碼示例展示如何通過 API 創建表示 lambda 表達式:num => num == 0

1             //通過 Expression 類創建表達式樹
2             //  lambda:num => num == 0
3             ParameterExpression pExpression = Expression.Parameter(typeof(int));    //參數:num
4             ConstantExpression cExpression = Expression.Constant(0);    //常量:0
5             BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression);   //二元表達式:num == 0
6             Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression);  //lambda 表達式:num => num == 0

  代碼使用 Expression 類的靜態方法進行創建。

 

三、解析表達式樹 

   下列代碼示例展示如何分解表示 lambda 表達式 num => num == 0 的表達式樹。

1             Expression<Func<int, bool>> funcExpression = num => num == 0;
2 
3             //開始解析
4             ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表達式參數
5             BinaryExpression body = (BinaryExpression)funcExpression.Body;  //lambda 表達式主體:num == 0
6 
7             Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");

 

 

 

四、表達式樹永久性

  表達式樹應具有永久性。(類似字元串)  這意味著如果你想修改某個表達式樹,則必須複製該表達式樹然後替換其中的節點來創建一個新的表達式樹。  你可以使用表達式樹訪問者遍歷現有表達式樹。  

五、編譯表達式樹

  Expression<TDelegate> 類型提供了 Compile 方法以將表達式樹表示的代碼編譯成可執行委托。

  示例

1             //創建表達式樹
2             Expression<Func<string, int>> funcExpression = msg => msg.Length;
3             //表達式樹編譯成委托
4             var lambda = funcExpression.Compile();
5             //調用委托
6             Console.WriteLine(lambda("Hello, World!"));
7 
8             //語法簡化
9             Console.WriteLine(funcExpression.Compile()("Hello, World!"));

 

 

 

 

六、執行表達式樹

  執行表達式樹可能會返回一個值,也可能僅執行一個操作(例如調用方法)。

  只能執行表示 lambda 表達式的表達式樹。表示 lambda 表達式的表達式樹屬於 LambdaExpression 或 Expression<TDelegate> 類型。若要執行這些表達式樹,需要調用 Compile 方法來創建一個可執行委托,然後調用該委托。
 1             const int n = 1;
 2             const int m = 2;
 3 
 4             //待執行的表達式樹
 5             BinaryExpression bExpression = Expression.Add(Expression.Constant(n), Expression.Constant(m));
 6             //創建 lambda 表達式
 7             Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression);
 8             //編譯 lambda 表達式
 9             Func<int> func = funcExpression.Compile();
10 
11             //執行 lambda 表達式
12             Console.WriteLine($"{n} + {m} = {func()}");

 

七、修改表達式樹 

   該類繼承 ExpressionVisitor 類,並且專用於修改表示條件 AND 運算的表達式。它將這些運算從條件 AND 更改為條件 OR。為此,該類將重寫基類型的 VisitBinary 方法,這是因為條件 AND 表達式表示為二元表達式。在 VisitBinary 方法中,如果傳遞到該方法的表達式表示條件AND 運算,代碼將構造一個包含條件 OR 運算符(而不是條件 AND 運算符)的新表達式。如果傳遞到 VisitBinary 的表達式不表示條件 AND運算,則該方法交由基類實現來處理。  基類方法構造類似於傳入的表達式樹的節點,但這些節點將其子目錄樹替換為訪問器遞歸生成的表達式樹。  

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             Expression<Func<int, bool>> funcExpression = num => num == 0;
 6             Console.WriteLine($"Source: {funcExpression}");
 7 
 8             var visitor = new NotEqualExpressionVisitor();
 9             var expression = visitor.Visit(funcExpression);
10 
11             Console.WriteLine($"Modify: {expression}");
12 
13             Console.Read();
14         }
15 
16         /// <summary>
17         /// 不等表達式樹訪問器
18         /// </summary>
19         public class NotEqualExpressionVisitor : ExpressionVisitor
20         {
21             public Expression Visit(BinaryExpression node)
22             {
23                 return VisitBinary(node);
24             }
25 
26             protected override Expression VisitBinary(BinaryExpression node)
27             {
28                 return node.NodeType == ExpressionType.Equal
29                     ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄個表達式:用 != 代替 ==
30                     : base.VisitBinary(node);
31             }
32         }
33     }

 

 

 

八、調試

  8.1 參數表達式

1             ParameterExpression pExpression1 = Expression.Parameter(typeof(string));
2             ParameterExpression pExpression2 = Expression.Parameter(typeof(string), "msg");

圖8-1

圖8-2

   從 DebugView 可知,如果參數沒有名稱,則會為其分配一個自動生成的名稱。

 

1             const int num1 = 250;
2             const float num2 = 250;
3 
4             ConstantExpression cExpression1 = Expression.Constant(num1);
5             ConstantExpression cExpression2 = Expression.Constant(num2);

圖8-3

圖8-4

 

1             Expression lambda1 = Expression.Lambda<Func<int>>(Expression.Constant(250));
2             Expression lambda2 = Expression.Lambda<Func<int>>(Expression.Constant(250), "CustomName", null);

圖8-5

圖8-6

   觀察 DebugView ,如果 lambda 表達式沒有名稱,則會為其分配一個自動生成的名稱。

 

小結

 

 

 


【原文鏈接】http://www.cnblogs.com/liqingwen/p/5868688.html 

 

預覽版,更新於09/16

 

 


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

-Advertisement-
Play Games
更多相關文章
  • 1.安裝git 2.創建用戶與授權 3.git 使用 ...
  • 1.安裝vsftpd 2.配置vsftpd.conf 3.添加ftp用戶 4.上傳許可權 5.設置vsftp 開機啟動 6.添加防火牆 ...
  • 每個人心裡都有一個建站夢,所以今天作為我第一篇文章,就給大家圓了這場夢。 今天我來詳細的一步一步帶領大家利用WordPress程式來建立自己的小站以及解決直接功能變數名稱訪問(本地安裝wordpress請閱讀《本地安裝WordPress》),首先建議大家在跟著我的步驟準備開始的時候先看看我的另一篇文章《Wo ...
  • I/O: 系統設定 預設輸入設備:標準輸入,STDIN,0 預設輸出設備:標準輸出,STDOUT,1 標準錯誤輸出:STDERR,2 屬於不同的數據流 標準輸入:鍵盤 標準輸出和錯誤輸出:顯示器 I/O重定向: 輸出重定向: > :覆蓋輸出 >> :追加輸出 2>:錯誤輸出 2>>:追加錯誤輸出 正 ...
  • ColorConsole htmlagilitypack.1.4.9.5 經測試效率比 CsQueryLaster 高 csvhelper Extend Devlib系列一套 itextsharp litedb log4net microsoft.bcl一套,.net4 await 用 MySql.... ...
  • 分別使用Controller和Filter方法完成登錄驗證,對比二者的優劣 ...
  • 分析ASP.NET MVC中隱藏處理的方法,使用記憶體隊列記錄日誌防止併發錯誤,Log4Net的使用方法及簡單應用 ...
  • 在 GUI 中執行非同步操作 序 目錄 一、在 GUI 程式中執行非同步操作 下麵通過窗體示例演示以下操作-點擊按鈕後:①將標簽內容改成:“Doing”,並將按鈕禁用(表示執行中);②線程掛起3秒(模擬耗時操作);③將標簽內容改為:“Complete”,並啟用按鈕(表示執行完成); 可是執行結果卻是: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...