2012-11-04 31 views
2

好吧,我必須得到標題非常錯誤。更多的代碼,更少的字數:類型推斷推斷出類的範圍,但不包括方法,雖然它們是一樣的嗎?

public class Manager<T> where T : Control, new() 
{ 
    void Manage() 
    { 
     Do(t => IsVisible(t)); 
    } 

    bool IsVisible(T t) 
    { 
     return t.Visible; 
    } 

    S Do<S>(Func<T, S> operation) 
    { 
     return operation(new T()); 
    } 
} 

編譯器對Do感到高興。它可以輕鬆推斷出T類型。現在讓我說我有這個:

public static class Util 
{ 
    static void Manage() 
    { 
     Do(t => IsVisible(t)); //wiggly line here 
    } 

    static bool IsVisible<T>(T t) where T : Control 
    { 
     return t.Visible; 
    } 

    static S Do<S, T>(Func<T, S> operation) where T : Control, new() 
    { 
     return operation(new T()); 
    } 
} 

編譯器希望類型現在明確鍵入。以下是我認爲:

在第一類中T來自IsVisible方法,其中有T過載和T被稱爲遍佈Manager類,沒什麼大不了容易推斷出來。但在第二種情況下,T被指定爲該方法的通用約束,可能難以推斷。好。

但是,這並不工作之一:

public static class Util 
{ 
    static void Manage() 
    { 
     Do(t => IsVisible(t)); //still wiggly line 
    } 

    static bool IsVisible(Control t) 
    { 
     return t.Visible; 
    } 

    static S Do<S, T>(Func<T, S> operation) where T : Control, new() 
    { 
     return operation(new T()); 
    } 
} 
  1. 爲什麼不編譯器推斷在最後一種情況下T

  2. 更重要的是,最後一種情況與第一種情況有什麼不同?在第一種情況下,編譯器必須從IsVisible方法推斷它,然後一路回去檢查TIsVisible中的類別,其中在最後一種情況下它在IsVisible方法中容易獲得。所以我認爲第三種情況比第一種情況更容易。

回答

4

(第一種情況)

編譯器是高興的事情做。它可以輕鬆推斷出T型。

它根本不推斷TT是類的類型參數:

public class Manager<T> where T : Control, new() 

(第二種情況)

編譯器想要的類型到現在爲止進行顯式類型。

我假設你在管理代碼的意思是:

Do(t => IsVisible(t)) 

這是正確的。 認爲T的類型應該在這裏?你如何期望編譯器推斷它?

(第三種情況,該方法是IsVisible(Control t)

爲什麼不編譯器推斷T在最後一種情況?

它不能從參數中這樣做。這聽起來像你期望它能夠計算出lambda表達式的主體可以工作的每種類型......並且類型推斷根本就不會以這種方式工作。您可以輕鬆地給編譯器足夠的信息,但:

Do((Control t) => IsVisible(t)); 

更重要的是,如何不同的是,從第一最後一種情況?

在第一種情況下,T不是Do方法的類型參數。編譯器只有需要推斷S,它可以從lambda表達式的返回類型中執行。它不需要爲T執行任何推斷,因爲這已經是「已知的」。 (它仍然是通用的,但並不需要推斷用於該方法調用。)首先構造Manager的實例時需要提供T的類型,因此它有效地移動了該決定。

有關類型推斷的所有細節,請參閱C#4規範(或C#3或C#5規範中的等效部分)的第7.5.2節。我建議先喝一杯濃咖啡:)

+0

Jon優秀的答案。對我很有啓發的真正答案是,在第一種情況下「T」不是被推斷出來的。我知道編譯器對第二種情況推斷類型有點苛刻,但我認爲如果從第三種情況推斷出類型,C#會更好。你的工作是受歡迎的。感謝你 – nawfal

+0

喬恩,你不覺得它是C#的弱點,它不能從我的第三種情況推斷類型?如果重載'IsVisible',肯定會出現很多不明確的情況,但至少可以在編譯時導致模糊錯誤,就像它在其他情況下一樣 – nawfal

+0

@nawfal:不是。鑑於類型推理規則已經非常複雜,我不想讓它們變得更復雜。如果你認爲你可以做得更好,我建議你試着寫出第三個案例需要編寫的規則。如果你能想出一個並不複雜的公式,我相信C#團隊很樂意聽到你的消息。 –