Reputation: 19820
Let's have the following simplified code:
UPDATE: The methods actually returns an object with generic type <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> ...
}
This code fails in runtime: Object reference not set to an instance of an object.
I have realized that compiler chooses the second overload of Foo
with Task<T>
argument. And therefore it fails when trying to await null
.
Maybe it is correct behavior according the C# spec, but it can cause real troubles, since it is not the right overload that programmer wanted. If it is not a bug in specification or in compiler, shouldn't compiled show some warning in similar cases? What is the most convenient way to tell the compiler to choose the first overload?
Upvotes: 2
Views: 63
Reputation: 1491
Overloads are chosen based on the compile time type, not the run time type, so something like this should work:
void Main()
{
object value = null;
Foo<object>(value);
}
As mentioned in a deleted answer, you can also just cast it to an object first:
Foo<object>((object)null);
or
Foo<object>(null as object);
Upvotes: 1
Reputation: 4017
In overload resolution, if null
is passed, then is chosen the method with the "most" derived type. In your case, Task
inherits from Object
, so async void Foo<T>(Task<T> task)
is called.
If you called Foo<string>(null);
then the compiler gave an error because Task
doesn't inherit from string
(nor string
inherits from Task
)
Upvotes: 2