I'm running into an issue where some test code for a library I'm writing won't compile due to an ambiguous call but the usage seemed clear to me. Upon further investigation I've found that adding throw
inside a lambda that has no return value seems to be inferred as a Func<T>
of any T
and not an Action
as I would expect.
Contrived example below (can paste into .NET Fiddle)
using System;
public class Program
{
class Foo
{
public void Method(Action action)
{
Console.WriteLine("Method A: " + action.GetType());
}
public void Method(Func<int> func)
{
Console.WriteLine("Method B: " + func.GetType());
}
/* // second call to Method becomes ambiguous if this is commented out.
public void Method(Func<bool> func)
{
Console.WriteLine(func.GetType());
}
*/
}
public static void Main()
{
var foo = new Foo();
foo.Method(() => { });
foo.Method(() => { throw new Exception("Foo!"); });
}
}
Which results in
Method A: System.Action
Method B: System.Func`1[System.Int32]
Maybe it assumes Func<object>
because with a throw it can't infer any return type... But why can't it? And why would it infer and call the concrete Func<int>
?
Additionally, if I try to create an implicit Func<string>
like so:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return "foo";
});
I get three separate compile errors I've not encountered before:
Compilation error (line 38, col 16): Cannot implicitly convert type 'string' to 'int'
Compilation error (line 38, col 16): Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type
Compilation error (line 38, col 9): Anonymous function converted to a void returning delegate cannot return a value
Researching these still doesn't make much sense in the contrived example above because these errors kinda contradict themselves. If the compiler can figure out it was returning string
and can't convert to int
, why is it then upset about about different return types or a void delegate returning a value?
Can anyone shed some light on why the compiler seems to have trouble understanding my intent? Is this a C# limitation or am I not seeing the ambiguity?
Func<string>
errors occur because there are two overloads and non of them accept a function that returns a string. First two errors: the compiler explains why it can't resolve the overload to that taking aFunc<int>
. Third error: the compiler explains why it can't resolve the overload taking anAction
. – ArynFunc<string>
, which makes the third confusing as it implies it has inferred the lambda as avoid
returningdelegate
. Additionally, the second error in isolation seems strange, there is only one return type. Why does addingthrow
make the compiler think there are multiple return types? – Kannadathrow
does not make the compiler think that. It does not think that – Arynthrow...
can be considered an expression instead of a statement? – CarawayCannot infer lambda expression argument from usage. Did you mean Action or Func<int>?
– Nodal