[C#] 只是想簡單說下表達式樹 - Expression Trees

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

只是想簡單說下表達式樹 - Expression Trees 目錄 簡介 Lambda 表達式創建表達式樹 API 創建表達式樹 解析表達式樹 表達式樹的永久性 編譯表達式樹 執行表達式樹 修改表達式樹 調試 簡介 表達式樹以樹形數據結構表示代碼,其中每一個節點都是一種表達式,比如方法調用和 x < ...


只是想簡單說下表達式樹 - Expression Trees

 

目錄

 

簡介

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

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

  表達式樹還能用於動態語言運行時 (DLR) 以提供動態語言和 .NET Framework 之間的互操作性。 

 

一、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 類,通過 Visit 方法間接調用 VisitBinary 方法將 != 替換成 ==。基類方法構造類似於傳入的表達式樹的節點,但這些節點將其子目錄樹替換為訪問器遞歸生成的表達式樹。  

 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

   從 DebugView 可知,float 比 int 多了個尾碼 F。

 

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 

【參考】微軟官方文檔

 

 


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

-Advertisement-
Play Games
更多相關文章
  • 1、查詢cpu的相關 a、查詢CPU的統計信息 使用命令:lscpu 得到的結果如下: b、查詢每個CPU信息 使用的命令:cat /proc/cpuinfo 得到如下結果: 2、查詢所有的pci設備信息(pci是一種匯流排,而通過pci匯流排連接的設備就是pci設備了,如今,我們常用的設備很多都採用p ...
  • Win10 連接L2TP VPN 失敗解決方法 iOS系統不知道在什麼時候,已經不支持PPTP VPN。偶爾的機會剛好看到github上的一鍵式VPN伺服器部署腳本 "setup ipsec vpn" ,就在 "VPS" 上部署了。系統是 Ubuntu 16.04 。 部署完成後在iPhond和iP ...
  • Ubuntu16.04 LTS下apt安裝WireShark 安裝與配置 1. 首先通過apt安裝WireShark: 會同時安裝許多的依賴包,其中包括一個叫做wireshark common的包,在dpkg預配置時會彈出對話解釋安裝選項,大意是 可以被安裝成允許在wireshark用戶組中的用戶抓 ...
  • 模式:pattern 正則: grep:基本正則 Extended grep:擴展正則 基本正則: . :任意單個字元 []:指定範圍內 [^]:指定範圍外 次數匹配 *:字元出現任意次 ?:字元出現0次或1次 \{m,n\}:字元至少出現m次,至多出現n次 \{1,\}:字元至少出現1次 .*:匹 ...
  • 引言 基於生成圖片實現了一個手機號轉圖片的需求。 內容也很簡單,直接用手機號生成一個png圖片。就是為了背景透明以便其他地方調用。 有無鋸齒主要依靠一句代碼:g.TextRenderingHint= TextRenderingHint.AntiAlias; 生成圖片 1、有鋸齒 2、無鋸齒 生成方法 ...
  • 操作步驟: 給頁面隱藏TextBox賦值,然後觸發ASP.NET change事件,調用ASP.NET後臺方法,調用後執行客戶端腳本this.RegisterClientScriptBlock(DateTime.Now.ToString(), script); 執行頁面的script;頁面的scri ...
  • System.Data.OleDb.OleDbException: 未指定的錯誤的解決方法 ...
  • 很多時候我們在使用Lambda表達式查詢時,比如使用Lambda表達式查詢用戶數據,有時候會用電話或郵箱去查詢用戶信息,有時候又會用戶名去查詢用戶信息 其實查詢的結果都一樣,但唯一的區別就是Lambda表達式中的條件不一樣,那麼能不能只寫一個查詢方法,而實現Lambda表達式中Where的有查詢條件 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...