这是重载分辨率的预期行为吗?

时间:2015-07-16 12:11:58

标签: c# .net overload-resolution

让我们有以下简化代码:

更新:这些方法实际上会返回一个通用类型为<T>的对象。

void Main()
{
    Foo<object>(null);
}

Bar<T> Foo<T>(T value) // first
{
    Console.WriteLine("Value: {0}", value);
    // return new Bar<T> ...
}

async void Foo<T>(Task<T> task) // second
{
    Console.WriteLine("Value from task: {0}", await task);
    // return new Bar<T> ...
}

此代码在运行时失败:Object reference not set to an instance of an object.我已经意识到编译器选择带Foo参数的Task<T>的第二个重载。因此在尝试等待null时失败了。

根据C#规范,它可能是正确的行为,但它可能会导致真正的麻烦,因为它不是程序员想要的正确的重载。如果它不是规范或编译器中的错误,不应该编译在类似的情况下显示一些警告?告诉编译器选择第一个重载最方便的方法是什么?

2 个答案:

答案 0 :(得分:2)

在重载决策中,如果传递null,则选择具有“最”派生类型的方法。在您的情况下,Task继承自Object,因此会调用async void Foo<T>(Task<T> task)

如果您调用Foo<string>(null);,则编译器会发出错误,因为Task未从string继承(string继承自Task

答案 1 :(得分:1)

根据编译时类型而不是运行时类型选择重载,所以这样的事情应该有效:

void Main()
{
    object value = null;
    Foo<object>(value);
}

如删除的答案中所述,您也可以先将其强制转换为对象:

Foo<object>((object)null);

Foo<object>(null as object);