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

Is it an expected behavior in overloading resolution?

让我们使用以下简化代码:

更新: 方法实际上 returns 具有泛型类型的对象 <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# 规范,这可能是正确的行为,但它会导致真正的麻烦,因为它不是程序员想要的 正确 重载。如果它不是规范或编译器中的错误,编译后是否应该在类似情况下显示一些警告?告诉编译器选择第一个重载的最方便的方法是什么?

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

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

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

Foo<object>((object)null);

Foo<object>(null as object);

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

如果你调用 Foo<string>(null); 那么编译器会给出一个错误,因为 Task 没有继承自 stringstring 也没有继承自 Task