2011-04-28 131 views
9


我使用通用的,可爲空的有這樣的代碼:泛型類型參數和可空方法重載

// The first one is for class 
public static TResult With<TInput, TResult>(this TInput o, 
      Func<TInput, TResult> evaluator) 
    where TResult : class 
    where TInput : class 

// The second one is for struct (Nullable) 
public static TResult With<TInput, TResult>(this Nullable<TInput> o, 
      Func<TInput, TResult> evaluator) 
    where TResult : class 
    where TInput : struct 

請注意TInput約束,一個是類,另一種是結構。然後我使用它們:

string s; 
int? i; 

// ... 

s.With(o => ""); 
i.With(o => ""); // Ambiguos method 

它會導致Ambiguos錯誤。但我也有另一對:

public static TResult Return<TInput, TResult>(this TInput o, 
      Func<TInput, TResult> evaluator, TResult failureValue) 
    where TInput : class 

public static TResult Return<TInput, TResult>(this Nullable<TInput> o, 
      Func<TInput, TResult> evaluator, TResult failureValue) 
    where TInput : struct 

這一個成功編譯

string s; 
int? i; 

// ... 

s.Return(o => 1, 0); 
i.Return(o => i + 1, 0); 

我沒有線索,爲什麼發生這種情況。第一個看起來不錯,但編譯錯誤。第二個('Return')應該是錯誤的,如果第一個是,但是編譯成功。我錯過了什麼?泛型方法中

+0

就像一個樣式註釋,我會避免使用lambda參數的相同名稱作爲範圍內的變量。 – 2011-04-28 07:19:51

+0

啊對,那實際上會導致編譯錯誤。我只是匆匆粘貼和編輯代碼。 – 2011-04-28 07:26:37

回答

10

限制,同時選擇超載不考慮 - 他們檢查後過載已被選定

參數類型內的約束條件是作爲選擇過載的一部分進行檢查。這有點令人困惑,但它最終有意義。

我對此有一個blog post這可能有助於進一步瞭解它。

另外請注意,你的第二個例子有額外的參數,它有助於類型推斷,這是兩者之間的區別。 TResult被推斷爲int,其防止第一超載有效 - 不存在從(int? x) => x + 1Func<int?, int>的轉換,而(int x) => x + 1Func<int, int>的轉換。

+0

我現在很感興趣,我正試着理解你的最後一段。兩個Func <>委託都根本不使用空(int?)。只有第一個參數是。 – 2011-04-28 07:24:43

+0

@Hendry:在每種情況下的第一個重載都會將'TInput = int?'視爲'int?'調用它。 'evaluateator'參數類型因此是'Func '。 – 2011-04-28 07:26:53

+0

哦,我看到了,這就是爲什麼基於lambda函數的重載分辨率在第一個「返回」失敗並流向第二個的原因。非常感謝。 – 2011-04-28 07:29:57