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?
The lambda functions do not need a return statement, they always return a single expression. Use lambda functions when an anonymous function is required for a short period of time. — I don’t why they say this, if you know, please let me know, I’m curious. What is the syntax of lambda functions? The expression is always executed and returned.
The lambda function can take many arguments but can return only one expression. Here the expression is nothing but the result returned by the lambda function. Lambda functions are syntactically restricted to return a single expression. You can use them as an anonymous function inside other functions.
Lambda functions are frequently used with higher-order functions, which take one or more functions as arguments or return one or more functions. A lambda function can be a higher-order function by taking a function (normal or lambda) as an argument like in the following contrived example:
Thus, the lambda won't get run until after the start method parameter gets garbage collected. Java has to make a copy of start in order for this lambda to live outside of this method. 3.1. Concurrency Issues
As @Servy stated in the duplicated link
The rules for determining which overload is called are spelled out in section 7.5.3.3 of the C# specs. Specifically, when the parameter is an anonymous method, it will always prefer the overload who's delegate (or expression) has a return value over one that has no return value. This will be true whether it's a statement lambda or expression lambda; it applies to any form of anonymous function.
In the below code:
var foo = new Foo();
foo.Method(() => { });
foo.Method(() => { throw new Exception("Foo!"); });
Because () => { throw new Exception("Foo!");}
fits to either Action
or Func<int>
. And also, "when the parameter is an anonymous method, it will always prefer the overload who's delegate (or expression) has a return value over one that has no return value" then Func<int>
is selected.
Concerning other exceptions:
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
The above exceptions are because of bad output types
. In the test, you have called below anonymous method that returns a string
but it should return int
because your Func<int>
returns int
:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return "foo";
});
For avoiding exception you should return an int
:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return 1;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With