'Why does adding throw inside a lambda without a return value get inferred as a Func<T> and not as Action? [duplicate]

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?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source