C#为什么这种类型推断的方法调用不明确?

C#为什么这种类型推断的方法调用不明确?,c#,C#,以下两个函数试图复制C#6.0中可用的空条件运算符: 第二个功能是我遇到麻烦的地方。例如,给定一个int?编号我想写: var y = number.Bind(a => a + 1); 但是,这给了我以下错误: 以下方法或属性之间的调用不明确:“BindingExtensions.Bind(T,Func)”和“BindingExtensions.Bind(T?,Func)” 我猜这与匿名函数的类型推断和方法重载解析之间的相互作用有关。如果我将a的类型指定为int,那么它编译起来就很好了

以下两个函数试图复制C#6.0中可用的空条件运算符:

第二个功能是我遇到麻烦的地方。例如,给定一个
int?编号
我想写:

var y = number.Bind(a => a + 1);
但是,这给了我以下错误:

以下方法或属性之间的调用不明确:“BindingExtensions.Bind(T,Func)”和“BindingExtensions.Bind(T?,Func)”

我猜这与匿名函数的类型推断和方法重载解析之间的相互作用有关。如果我将a的类型指定为
int
,那么它编译起来就很好了

var y = number.Bind((int a) => a + 1);

然而,这显然是不可取的。有人能告诉我为什么编译器认为上面对bind的调用不明确和/或提供了一种解决方法吗?我知道我可以简单地对这两个函数进行不同的命名,但这有什么意思呢?

重载函数不能通过类型约束来消除歧义(请参见“”)。任何可为空的类型N都分别满足前者和后者的
Bind
定义所要求的
N:T
N:nullable
。我猜
number
属于
Nullable
或类似类型

var x = s.Bind(a => a.Substring(1));
这是明确的,因为
s
属于
string
类型,并且对于所有
T
string:Nullable
,因此只有第一个重载是可接受的

var y = number.Bind(a => a + 1);
这是不明确的,因为
a=>a+1
的类型可以推断为
Func
Func
。如果推断为
Func
则应用第一个重载,如果推断为
Func
则应用第二个重载

var y = number.Bind((int a) => a + 1);
例如,如果
number
的类型为
Nullable
,则这是明确的。对于所有
T
not
T:Nullable
T:int
的第一个重载,它不适用。对于第二个重载,您只需要
T:int
,这可以通过
T=int
轻松满足

    public static TResult Bind<T, TResult>(this T? obj, Func<T?, TResult> func)
    where T : struct
    {
        return obj.HasValue ? func(obj.Value) : default(TResult);
    }
publicstatictresult绑定(此T?obj,Func-Func)
其中T:struct
{
返回obj.HasValue?函数(obj.Value):默认值(TResult);
}

您可以删除第一个约束,而不需要第二个约束。当然,对于
null
值,
number.Bind(a=>a+1)
的结果将是
null
而不是0。但无论如何,这是我所期望的结果。@juharr,那会有点挫败目的。我希望匿名函数的输入永远不能为null,这就是为什么第二个函数对可为null的函数进行操作,但只向匿名函数传递一个T。您的函数不会被传递一个
null
,因为
obj==null
对于
null
HasValue
值为false的
。当然,这意味着您的函数必须期望
int
而不是
int
,但这正是我所期望的。@juharr我不同意,我希望
int
而不是
int?
,因为它永远不会为null。我的灵感来自monad的函数思想(这就是为什么我将函数命名为
Bind
)。我将
Bind
视为将变量从其可为null的上下文中提取出来(如果可以)并对其进行操作。类型约束是。
nullable
本身就是一个结构,不是吗?那么
int?
如何满足类约束呢?@Micah谢谢你指出这个错误。我已经修改了我对这个问题的解释。为了解决这个问题,你需要解释为什么我认为这确实有效,但我真的很想看到解释。我想我不认为OP会对向函数传递一个
Nullable
感到满意。对,这会起作用,但请看我对这个问题的评论。func的参数应该是
T
而不是
T?
,因为它永远不会为空。@micahahn如果参数永远不会为空,那么如果参数是
T
T?
,func(T)委托需要“相同的”对象类型T。是的,如果“int?number=null”,它可以是空值,您仍然可以使用Bind函数,因为obj.HasValue将返回false。
var y = number.Bind((int a) => a + 1);
    public static TResult Bind<T, TResult>(this T? obj, Func<T?, TResult> func)
    where T : struct
    {
        return obj.HasValue ? func(obj.Value) : default(TResult);
    }