2010-08-20 89 views

回答

12

表達式樹的主要用途是用於進程外LINQ提供程序,如LINQ to SQL。

當編寫這樣的事:

var query = people.Where(x => x.Age > 18) 
        .Select(x => x.Name); 

那些lambda表達式可以被轉換爲代表,然後可以執行(因爲它們是在LINQ到對象)它們可以是轉換爲表達式樹,可以由查詢源進行分析並據此採取行動(例如將它們轉換爲SQL,Web服務調用等)。不同之處在於表達式樹代表數據。如有必要,它們可以編譯成代理,但通常(在LINQ中)它們從來不會被直接執行 - 只是經過檢查才能找出它們包含的邏輯。

表達式樹還廣泛用於動態語言運行時,它們表示在評估動態表達式時應執行的代碼。表達式樹非常適合這種情況,因爲它們可以被組合並再次分解,並且在它們被編譯後,生成的IL被正常編譯爲JIT。

大多數開發人員將永遠不需要混淆表達式樹API,儘管它還有其他一些用途。

+0

謝謝喬恩。我很想獲得一個關於我可以在哪裏使用它的實例。我有了這個概念,但除非我想不出使用Expression Tree比傳統的做法更好的場景,否則我不會感到舒服。 – DotNetInfo 2010-08-20 06:40:06

+0

@Nimesh:它*可以偶爾用於創建需要使用反射的重構防禦程序。通過將lambda表達式轉換爲委託而不是名稱(作爲字符串)來指定屬性,可以在執行時添加字符串並知道它是正確的。但這確實是一個邊緣案例 - 主要針對LINQ和DLR(編輯反映後者)。 – 2010-08-20 06:45:32

5

除了LINQ,另一個非常簡單的用例是提取一個屬性的名稱和值。我在流利的API中使用它來驗證數據傳輸對象。傳遞一個lambda參數來定義名稱和值是比較安全的,而不是爲名稱指定第二個字符串參數,並冒着開發人員錯誤的風險。

下面是一個例子(減去所有的安全檢查和其他管家):

public Validator<T> Check<T>(Expression<Func<T>> expr) { 
    // Analyse the expression as data 
    string name = ((MemberExpression) expr.Body).Member.Name; 
    // Compile and execute it to get the value 
    T value = (expr.Compile())(); 
    return new Validator<T>(name, value); 
} 

使用示例:

Check(() => x.Name).NotNull.MinLength(1); 
Check(() => x.Age).GreaterThan(18); 
+0

非常好的驗證API,雖然性能可能不太好,因爲表達式編譯 – 2010-08-20 08:02:55

+0

是的,會有性能開銷。總而言之,我認爲可靠性的提高是值得的。另外,每個屬性只編譯一次,然後您可以儘可能多地敲擊構造的驗證器對象。 – 2010-08-20 08:36:31

4

我用表達式樹作空安全評估:

string name = myObject.NullSafeEval(x => x.Foo.GetBar(42).Baz.Name, "Default"); 

此方法分析並重寫表達式樹以在每個pro之前插入空檢查perty或方法調用沿「路徑」Name。如果沿途遇到null,則返回默認值。

SEE實施here

表達式樹也常用,以避免在一個字符串硬編碼它的名字指的是一個屬性:

private string _foo; 
public string Foo 
{ 
    get { return _foo; } 
    set 
    { 
     _foo = value; 
     OnPropertyChanged(() => Foo); 
     // Rather than: 
     // OnPropertyChanged("Foo"); 
    } 
} 

static string GetPropertyName<T>(Expression<Func<T>> expr) 
{ 
    var memberExpr = expr.Body as MemberExpression; 
    if (memberExpr == null) 
     throw new ArgumentException("expr", "The expression body must be a member expression"); 
    return memberExpr.Member.Name; 
} 

protected void OnPropertyChanged<T>(Expression<Func<T>> expr) 
{ 
    OnPropertyChanged(GetPropertyName(expr)); 
} 

這使得編譯時檢查和名稱重構

+0

很酷。如果只在語言中加入某種語法等價物...... 2010-08-20 08:40:23

+0

@Christian Hayter:你能舉個例子嗎? – Douglas 2010-08-20 13:02:34

+0

@Douglas:一個什麼樣的例子? – 2010-08-20 14:44:32

相關問題