2011-01-13 48 views
3

因此,我正在處理一個需要解析表達式樹的項目。我得到了大部分工作,但我遇到了一些問題。表達式樹解析,變量結束爲常量

我一直在尋找表達式樹上的StackOverflow上的其他問題,但似乎無法找到我的問題的答案,所以在這裏。

我的問題是常數和變量之間的差異(或缺乏)。讓我開始用一個例子:

user => user.Email == email 

這顯然不是一個常量而是變量,但是這個最終表達式樹的地方是一個常量表達式。如果你看一看錶達式本身,它看起來有點奇怪:

Expression = {value(stORM.Web.Security.User+<>c__DisplayClassa)} 

如果我們再舉一個例子:

task => task.Status != TaskStatus.Done && t.Status != TaskStatus.Failed 

在這裏,我使用ENUM(TaskStatus)。

所以我的問題是,在樹解析中,我似乎最終在兩種情況下都有一個ConstantExpression,我真的需要能夠將它們分開。這些只是一個例子,所以我所要求的是將這兩種類型的表達式相互通知的一種通用方式,所以我可以在解析中以兩種不同的方式處理。

編輯:好的,我的例子可能不清楚,所以我會再試一次。第一個例子:

User user = db.Search < User>(u => u.Email == email);

我正在嘗試查找給定電子郵件地址的用戶。我正在解析這個存儲過程,但除了我想的點。

第二個例子:

的IList <任務>任務= db.Search(!噸=> t.Status = TaskStatus.Done & & t.Status = TaskStatus.Failed);

在這裏我試圖找到狀態不同於完成和失敗的所有任務。 這又是解析到一個存儲過程。在第一個示例中,我的代碼需要確定存儲過程需要一個輸入參數,即電子郵件變量的值。在第二個示例中,我不需要任何輸入參數,我只需創建用於選擇狀態與「完成」和「失敗」不同的任務的SQL。

再次感謝

回答

2

這個名字有點不幸,它實際上並不是一個常量。

它只是指表達式之外的值。

2

捕獲的變量(第一種情況與email)通常表示捕獲類實例一個ConstantExpression,具有MemberExpressionFieldInfo爲「可變」 - ,如果你有:

private class CaptureClass { 
    public string email; 
} 
... 
var obj = new CaptureClass(); 
obj.email = "[email protected]"; 

這裏,obj是表達式中的常量。所以:如果你看到一個MemberExpression(的一個字段)到一個ConstantExpression,它是可能是一個被捕獲的變量。你也可以檢查CompilerGeneratedAttribute上的捕獲級...

一個文字常數通常只是ConstantExpression;事實上,這將是很難想象,你用一個恆定的成員的情形,除非你能像:

() => "abc".Length 

但這裏.Length財產(非現場),也可能是字符串沒有[CompilerGenerated]

+0

我的問題可能不夠清楚,但Email實際上是用戶對象的屬性。 –

+0

@SteenT - 表達式樹是什麼樣的?它*可能是同樣的東西,默默地捕獲'this'(因爲'email'隱含地是'this.email')。所以我*可能*期望'會員(「電子郵件」,會員(「這個」,captureClass))(如果你明白我的意思) –

+0

@SteenT - 啊,在我的回答中,我在談論右邊的'電子郵件'手邊。上面的註釋應該解釋左邊的'user.Email' ... –

3

所以從表達的角度來看,這個值是一個常數。它不能被表達式改變。

你擁有的是一個潛在的開放式關閉 - 即值可以在表達式執行之間改變,但不會在執行期間改變。所以這是一個「不變的」。這是函數式編程和無法實現的編程世界之間的範例區別。

考慮

 int a =2; 
     Expression<Func<int, int>> h = x=> x+ a; 
     Expression<Func<int, int>> j = x => x +2; 
     a = 1; 

術語一個是其成員接入到該包紮並訪問堆棧上的變量的匿名類。第一個節點是一個MemberAccess節點,然後是該節點 - 該表達式是一個常量。

對於上面的代碼:

((SimpleBinaryExpression)(h.Body)).Right 
{value(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a} 
    CanReduce: false 
    DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a" 
    Expression: {value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)} 
    Member: {Int32 a} 
    NodeType: MemberAccess 
    Type: {Name = "Int32" FullName = "System.Int32"} 

而這下面的常數:

((MemberExpression)((SimpleBinaryExpression)(h.Body)).Right).Expression 
{value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)} 
    CanReduce: false 
    DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0)" 
    NodeType: Constant 
    Type: {Name = "<>c__DisplayClass0" FullName = "WindowsFormsApplication6.Form1+<>c__DisplayClass0"} 
    Value: {WindowsFormsApplication6.Form1.} 
     } 
    } 

普通的老2出來的:

((SimpleBinaryExpression)(j.Body)).Right 
{2} 
    CanReduce: false 
    DebugView: "2" 
    NodeType: Constant 
    Type: {Name = "Int32" FullName = "System.Int32"} 
    Value: 2 

,所以我不知道這是否有助於你。您可以通過查看父節點或父節點訪問的對象的類型來進行判斷。


添加爲你澄清的結果 -

所以當你說

user => user.Email == email 

你的意思是查找所有用戶的電子郵件等於傳入的參數 - 但是這種聯繫表達意味着完全不同。

你想說什麼

Expression<Func<User, string, bool>> (user, email) => user.Email == email 

這樣的電子郵件,現在將是一個參數。如果你不喜歡,你可以做另一件事。

第二個例子會工作得很好 - 不需要額外的參數consts是const。

t => t.Status != TaskStatus.Done && t.Status != TaskStatus.Failed 

編輯:添加另一種方式:

的,你必須做的就是你的代碼工作的事情,所以一個是聲明字符串電子郵件拉姆達外 - 這是一種笨拙。

你可以通過傳統的方式將它們放在特定的位置來識別參數 - 比如靜態類。然後,當通過Lambda時,你不必看一些可怕的cloture對象 - 但是你的製作很好的靜態類。

public static class Parameter 
{ 
    public static T Input<T>(string name) 
    { 
     return default(T); 
    } 
} 

然後你的代碼如下所示:

Expression<Func<User, bool>> exp = x => x.Email == Parameter.Input<String>("email"); 

然後,您可以遍歷樹 - 當你來到一個呼叫參數靜態類,你可以看看類型和名稱(在參數集合中)並關閉你去...

+0

我會根據你的建議來看看父節點,看看我得到了什麼!謝謝。我會在這裏張貼我的發現! –

+0

等一下 - 可能發生的事情是這樣的...你有一個本地用戶定義,並且試圖將該實例作爲一個整體。你可能想要做的是Expression > x => x.email == email;我認爲你可能在本地實例和期望的輸入之間感到困惑? – Neil

+0

增加了一些更多的問題來澄清問題。我仍然會看看父節點,看看我的位置。 –

0

只需檢查ConstantExpression的類型。任何'常量'ConstantExpression都有一個基本類型。