2013-12-18 38 views
9

我已經進行了如下推理測試:爲什麼C#無法從非泛型靜態方法的簽名推斷泛型類型參數類型?

static class InferenceTest { 
    static void TakeInt(int a) { } 
    static int GiveInt() { return 0; } 
    static int TakeAndGiveInt(int a) { return 0; } 

    static void ConsumeAction1<T>(Action<T> a) { } 
    static void ConsumeFunc1<T>(Func<T> f) { } 
    static void ConsumeFunc2a<T1, T2>(Func<T1, T2> f) { } 
    static void ConsumeFunc2b<T>(Func<int, T> f) { } 
    static void ConsumeFunc2c<T>(Func<T, T> f) { } 
    static void ConsumeFunc1Func2<T1, T2>(Func<T1> f1, Func<T1, T2> f2) { } 

    static void Main() { 
     ConsumeAction1(TakeInt);  //error 
     ConsumeFunc1(GiveInt);   //ok 
     ConsumeFunc2a(TakeAndGiveInt); //error 
     ConsumeFunc2b(TakeAndGiveInt); //ok 
     ConsumeFunc2c(TakeAndGiveInt); //error 
     ConsumeFunc1Func2(GiveInt, TakeAndGiveInt); //ok 
    } 
} 

結果似乎表明,C#編譯器無法推斷通用類型參數從非泛型方法組委託函數的參數。

我什麼困擾最深的是,C#是可以推斷Func<T1, T2>從方法的返回值類型變量在ConsumeFunc1Func2,但無法推斷類型Func<T, T>ConsumeFunc2c

這個問題類似於T of Func<S, T> is inferred from output of lambda expression only when S and T are different?的問題,但不是具有未知參數類型的lambdas,我們有非泛型方法組。

Why can't C# infer type from this seemingly simple, obvious case問題的答案類型的問題「爲什麼非模糊的非泛型方法不足以進行推理?」和「爲什麼參數類型和推理的返回值類型之間存在差異?」。

問題:

爲什麼C#編譯器推斷Func<T>使用的返回值的類型的類型,但沒有看到Func<T, T>情況下成功?

爲什麼C#編譯器推斷從Func<T1>Func<T1, T2>T1類型參數在ConsumeFunc1Func2,但不能推斷ConsumeFunc2cFunc<T, T>從自身T型參數,它似乎是更容易?

+0

在ConsumeFunc1Func2中,編譯仍然只從返回值推斷,而不是參數類型。 T1從GiveInt的返回值中解析出來,T2從TakeAndGiveInt的返回值中解析出來。因此,ConsumeFunc1Func2案例沒有增加額外的祕密。 – Baldrick

+1

我會很好的閱讀C#4.0規範的第7.5.2節。它非常易讀,描述了類型推斷的各個階段,以及它們與方法組的關係。 – Baldrick

+0

'ConsumeFunc2b'表明''Func '返回類型'T'可以從'TakeAndGiveInt'解析。但是當'?'也是'T'時,'ConsumeFunc2c'中的'Func '就是這種情況,編譯器似乎忘記了參數'T'與已經推斷的'T'相同。與'ConsumeFunc1Func2'成功不同。 –

回答

1

方法參數未被檢查。

如上所述,在ConsumeFunc1Func2中,編譯器僅從返回值推斷。 在ConsumeFunc2c中,TakeAndGiveInt簽名不被檢查,看它的方法參數類型是否實際上是相同類型的方法返回類型原因...方法參數未被檢查!

1

通常,方法名稱不會唯一標識方法組可以分配到的唯一類型Action<T>。例如,即使只有一個過載Fred並且需要一個Cat參數,那麼該過載不僅可以分配給Action<Cat>,還可以分配給其他類型,如Action<Mammal>Action<Animal>Action<Object>。雖然在某些情況下,一種類型的替代在各方面都會優於其他替代品,但並非總是如此。定義語言以要求指定委託類型更清晰,而不是讓編譯器試圖「猜測」,特別是因爲讓編譯器猜測意味着許多不應該突破變化的事情會是(例如添加一個方法重載可能會導致用於工作的類型推斷模糊不清)。