2016-08-17 52 views
0

這是代碼。是什麼讓C#編譯器輸出表達式樹而不是代碼?

int[] data = new int[] { 1, 2, 3, 4, 5 }; 
    var q1 = data.Select(x => 10 * x); 
    var q2 = data.AsQueryable().Select(x => 10 * x); 
    Expression<Func<int,int>> qe = (x) => 10 * x; 

在第一種情況下,編譯器生成評估表達式的代碼。輸出中沒有表達式樹。

它在第二次生成表達式樹(在調試時可見),它在運行時被編譯並執行以執行查詢(並且執行完全相同的操作)。

在第三種情況下,直接創建與(2)相同的lambda作爲表達式樹(而不是代碼)。

在這兩種情況下,什麼使編譯器生成表達式樹而不是代碼,還有其他有趣的情況嗎?

原因:我想在運行時「分離」表達式樹的頂層,然後編譯並執行較低層。我無法讓編譯器按我的方式做事!

+2

這是「編譯器如何編寫」的一個例子。它需要這樣做才能使表達式工作。這就好像返回'IEnumerable '的方法''可以使用'yield return'。支持語言功能的特殊編譯器操作。 – Enigmativity

+0

名單繼續。編譯器會以不同的方式處理'Nullable '類型。它可以爲'foreach'循環使用duck-typing。 LINQ查詢實際上只是重新排列的方法(通常是擴展方法,但不需要)。 「使用」陳述僅適用於一次性用品等。 – Enigmativity

+0

您的第一個陳述並非真正的表達;它是一個*構造函數調用。*兩個Select語句是Linq語句,它們作爲其正常操作的一部分生成表達式。第四個語句生成一個表達式,因爲您將表達式指定爲結果類型。 –

回答

3

EnumerableSelect方法接受Func<TSource,TResult>類型的參數。 QueryableSelect方法接受類型爲Expression<Func<TSource,TResult>>的參數。

就這麼簡單 - 如果編譯器有一個lambda表達式,它可以生成一個表達式或編譯lambda表達式,這個決定是基於它被要求創建的 - 如果它是某種類型的Expression,它將生成表達式樹。如果它是Func或其他委託類型,它將生成代碼。

+0

該死!這真的很簡單!如果參數派生自Delegate,則編譯器會生成代碼,如果派生自Expression,則編譯器會生成代碼,並且沒有其他選擇。謝謝! –

+1

請記住,代表可以跨越多行,但表達式樹的寫法與代表相同,例如, '表達式> lambda =()=> new int [] {1,2,3,4,5};'只能是一行。 – Sagi