Marťas
Marťas

Reputation: 1092

Why is this call ambiguous for compiler?

I am experimenting with async/await and I am getting compiler error for DoWorkAsync1.

Error CS0121 The call is ambiguous between the following methods or properties: Task.Run<TResult>(Func<TResult>) and Task.Run<TResult>(Func<Task<TResult>>)

For DoWorkAsync2 I added typecast to advice the compiler and that is OK. Why it has problems with DoWorkAsync1? DoWorkAsync3 does the same, only the function is anonymous and it has no problem too.

static int Pom() { return 42; }

static async Task<int> DoWorkAsync1()
{
    var operation = Task.Run<int>(Pom);
    return await operation;
}

static async Task<int> DoWorkAsync2()
{
    var operation = Task.Run<int>( (Func<int>)Pom );
    return await operation;
}

static async Task<int> DoWorkAsync3()
{
    var operation = Task.Run<int>(() => 42);
    return await operation;
}

Upvotes: 3

Views: 272

Answers (1)

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391336

The reason why you're getting this is that the return-type is not taken (enough) into account when determining overload candidates in C# 7.2 or older. As such, the list of potential candidates does not contain only 1 method, and the compiler halts with an ambiguity error.

This was improved on in C# 7.3:

  • For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set.

This also explains why your lambda works, it is not a method group conversion, a different part of the compiler kicks in and is apparently able to determine the correct overload.

And indeed, if I compile your code with C# 7.0, 7.1 or 7.2, I get:

[CS0121] The call is ambiguous between the following methods or properties: 'Task.Run<TResult>(Func<TResult>)' and 'Task.Run<TResult>(Func<Task<TResult>>)'

... but if I change it to 7.3, it compiles, and is using the Func<int> overload.

Upvotes: 3

Related Questions