这是重载分辨率的预期行为吗?
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
没有继承自 string
(string
也没有继承自 Task
)
让我们使用以下简化代码:
更新: 方法实际上 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
没有继承自 string
(string
也没有继承自 Task
)