2009-12-07 98 views
1

我正在給一些自定義對象添加LINQ接口,但是C# compiler fails on type inference。但是,我可以使用原始擴展方法編寫等效查詢,並且類型推導成功,所以我不確定編譯器如何將查詢表達式轉換爲擴展方法調用。LINQ查詢表達式翻譯器?

是否有工具或編譯器標誌,以便我可以查看編譯器從我的查詢表達式中生成的內容,所以我知道了這一點?

此代碼位於開源項目中,因此如果有幫助,我可以提供指向源代碼的鏈接。擴展方法的類型簽名有輕微的變化,以避免這種類型的推理錯誤,但是這些變體沒有我之後的語義。

+2

編譯器用於翻譯查詢表達式的精確系列步驟是在C#規範中,您可以從Internet獲得該規範。 – 2009-12-07 16:34:13

回答

4

您查詢綜合代碼爲:

from f1 in e1 
from f2 in e2 
from f3 in e3 
select f3 

你的方法調用的代碼是:

e1 
.SelectMany(f1 => e2) 
.SelectMany(f2 => e3), (f2, f3) => f3)) 

查詢翻譯過程如下。首先,我們應對前兩個FROM子句:

from f1 in e1 
from f2 in e2 
from f3 in e3 
select f3; 

這被翻譯成

from x in (e1) . SelectMany(f1 => e2 , (f1 , f2) => new { f1 , f2 }) 
from f3 in e3 
select f3; 

其中 「X」 是一個透明的標識符。由於e1,e2或e3都不使用任何範圍變量,因此這是一個透明標識符的事實是不相關的;不需要進一步重寫來處理透明標識符語義。

這一結果,然後轉化爲

((e1) . SelectMany(f1 => e2 , (f1 , f2) => new { f1 , f2 })) 
.SelectMany(x => e3 , (x , f3) => f3) 

我們可以消除一些人的括號:

e1 
.SelectMany(f1 => e2 , (f1 , f2) => new { f1 , f2 })) 
.SelectMany(x => e3 , (x , f3) => f3) 

顯然,這是從語法變換你手工完成,其中,召回而不同,是

e1 
.SelectMany(f1 => e2) 
.SelectMany(f2 => e3), (f2, f3) => f3)) 

如果您將e1,e2,e3替換爲實際值上面的語法轉換,得到的表達式傳遞類型推斷?

如果沒有,那麼問題是「爲什麼不?」你的代碼有問題,或者類型推理器有問題。如果類型推理者出現問題,請告訴我。

如果是這樣,那麼問題是「句法轉換過程有什麼問題」?如果語法轉換過程有問題,請再告訴我。

謝謝!

+0

順便說一句,f1和f2不在範圍內,因爲匿名類型現在封裝在將來。 – naasking 2009-12-07 19:32:14

+0

通過對擴展方法進行小調整來使用翻譯,可以在返回f3時正確編譯查詢,但f1和f2不在範圍內。問題在於我在未來的類型上運行,我只想從客戶端代碼中提取未來的價值。所以,通常的SelectMany的樣子:未來的SelectMany (這個未來 FUT,Func鍵> SEL,Func鍵 RES),但我需要它看起來像:未來的SelectMany (這個未來 FUT,Func鍵,未來> SEL ,Func ,Future ,Future > res)想法? – naasking 2009-12-07 19:34:28

+0

事實上,以下就足夠了: 未來的SelectMany (這個未來 FUT,Func鍵,未來> SEL,Func鍵,未來,R> RES) 這也不起作用。 – naasking 2009-12-07 19:35:34

1

您可以使用Reflector並關閉優化來查看您的代碼。

+0

不,如我所說查詢表達式的代碼不能編譯,所以我沒有什麼要檢查的。我正在尋找一些工具/技術來將查詢表達式的源代碼翻譯成使用等效擴展方法的源代碼,以便我可以看到爲什麼查詢表達式不會編譯。 – naasking 2009-12-07 04:11:20

+0

你可以發佈代碼嗎?也許如果我看看它,我可以幫助你弄清楚發生了什麼。 – 2009-12-07 04:12:17

+0

具有擴展方法的核心類,在427行及以後定義的SelectMany: http://sasa.svn.sourceforge.net/viewvc/sasa/trunk/Sasa/Futures.cs?revision=416&view=markup 測試,請參閱行93方法「testLinqSuccess」爲我正在描述的錯誤: http://sasa.svn.sourceforge.net/viewvc/sasa/trunk/Build/Tests/FutureTests.cs?revision=416&view=markup 有點更多背景:這些是使用期貨的異步計算。我的第一個版本的行爲就像Error monad,如果以前的異常失敗,所有後續的期貨都會失敗,但這不是所需的語義。我很欣賞任何見解。 – naasking 2009-12-07 04:31:35

0

Eric的概述讓我明白瞭如何處理這些查詢。問題在於我試圖以查詢翻譯不喜歡的方式限制正在操作的類型。

from x in Foo.Bar() 
... 

Foo。Bar()應該返回一個Future,x也應該是Future類型的,但這不適用於查詢翻譯。我通過增加另一層間接尋址來解決這個問題,基本上是將期貨包裝在一個異步類型中,這種異步類型只能用期貨實例化,即。

public sealed class Async<T> { internal T value; } 
public static class Async 
{ 
    public static Async<Future<T>> Begin<T>(Future<T> future) { ... } 
} 

然後,我可以寫上異步值查詢計算,所以表達式變成一樣的東西:

from x in Async.Begin(Foo.Bar()) 
... 

其中x是現在未來型的,我可以強制或推遲期貨和隨意承諾。

感謝大家的建議。查詢表達式轉換器內置到Visual Studio將是很好,但萬一有人在MS閱讀此。 ;-)