c#为什么这个类型推断方法调用有歧义

本文关键字:方法 调用 歧义 为什么 类型 | 更新日期: 2023-09-27 18:04:51

下面两个函数试图复制c# 6.0中可用的null条件运算符:

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);
}

第一个函数被限制为类,对于String s,我可以这样写:

var x = s.Bind(a => a.Substring(1));

第二个函数是我遇到麻烦的地方。例如,给定一个int? number,我想写:

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

调用在以下方法或属性之间是不明确的:'BindingExtensions.Bind<T,>(T, Func<T,>)'和'BindingExtensions.Bind<T,>(T?, Func<T,>)'

我猜这与匿名函数的类型推断和方法重载解析之间的相互作用有关。如果我指定a的类型为int,那么它可以正常编译。

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

然而,这显然是不理想的。谁能告诉我为什么编译器认为上面的调用绑定是模棱两可的和/或提供一种方法来解决这个问题?我知道我可以简单地用不同的名字命名这两个函数,但这有什么好玩的?

c#为什么这个类型推断方法调用有歧义

不能通过类型约束消除重载函数的歧义(参见"泛型约束,其中T: struct和T: class")。任何可空类型N都满足N : TN : Nullable<T>,分别满足Bind定义的要求。我猜number的类型是Nullable<int>或类似的。

var x = s.Bind(a => a.Substring(1));

这是明确的,因为sstring类型的,并且对于所有T而不是string : Nullable<T>,所以只有第一个重载是可接受的。

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

这是有歧义的,因为a => a + 1的类型可以被推断为Func<int?,int?>Func<int,int>。如果推断为Func<int?,int?>,第一个重载应用,如果推断为Func<int,int>,第二个重载应用。

var y = number.Bind((int a) => a + 1);
例如,如果numberNullable<int>类型,则

这是明确的。对于所有T不是T : Nullable<int>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);
    }