2011-04-28 136 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