以下函数对尝试复制C#6.0中可用的空条件运算符:
public static TResult Bind<T, TResult>(this T obj, Func<T, TResult> func)
where T : class
{
return obj == null ? default(TResult) : func(obj);
}
public static TResult Bind<T, TResult>(this Nullable<T> obj, Func<T, TResult> func)
where T : struct
{
return obj.HasValue ? func(obj.Value) : default(TResult);
}
Run Code Online (Sandbox Code Playgroud)
第一个函数被约束到类,并且String s允许我写一些类似的东西:
var x = s.Bind(a => a.Substring(1));
Run Code Online (Sandbox Code Playgroud)
第二个功能是我遇到麻烦的地方.例如,给int? number我一个我想写的:
var y = number.Bind(a => a + 1);
Run Code Online (Sandbox Code Playgroud)
但是,这给了我以下错误:
以下方法或属性之间的调用是不明确的:'BindingExtensions.Bind <T,TResult>(T,Func <T,TResult>)'和'BindingExtensions.Bind <T,TResult>(T?,Func <T,TResult >)"
我猜这与匿名函数的类型推断和方法重载决策之间的相互作用有关.如果我指定a的类型,int那么编译就好了.
var y = number.Bind((int a) => a + 1);
Run Code Online (Sandbox Code Playgroud)
然而,这显然不太理想.任何人都可以告诉我为什么编译器认为上面的绑定调用是模糊的和/或提供一种方法来解决这个问题?我知道我可以简单地命名这两个函数,但那有什么乐趣?
重载函数无法通过类型约束来消除歧义(请参阅“通用约束,where T : struct 和 where T : class ”)。任何可空类型 N 都满足N : T和N : Nullable<T>,分别是前一个和后一个Bind定义所要求的。我猜那number是类型Nullable<int>或类似的。
var x = s.Bind(a => a.Substring(1));
Run Code Online (Sandbox Code Playgroud)
这是明确的,因为sis 类型string并且对于所有Tnot 类型string : Nullable<T>,因此只有第一个重载是可接受的。
var y = number.Bind(a => a + 1);
Run Code Online (Sandbox Code Playgroud)
这是不明确的,因为 的类型a => a + 1可以被推断为Func<int?,int?>或Func<int,int>。如果推断为Func<int?,int?>第一过载,则适用,并且如果推断为Func<int,int>第二过载,则适用。
var y = number.Bind((int a) => a + 1);
Run Code Online (Sandbox Code Playgroud)
例如,如果number是 类型,则这是明确的。Nullable<int>对于所有TnotT : Nullable<int>和 的第一个重载T : int,因此它不适用。对于第二个重载,您只需要T : int它很容易满足T = int。