Search code examples
c#lambdamethod-group

Why does adding a return type prevent me from using method group syntax?


I'm trying to use a method group in a lambda expression, like this:

public class Foo { public void Hello(string s) { } }

void Test()
{
    // this works as long as Hello has a void return type
    Func<Foo, Action<string>> a = foo => foo.Hello;
}

When I change the return type of Hello to int, however, I get

'Bar.Hello(string)' has the wrong return type.

I've tried playing around with Func in place of Action, but that seems to prevent me from using the method group syntax.

Any ideas?

(My goal, fwiw, is to be able to refer to numerous methods that have different return types and lots of string arguments. I don't even intend to call them - I just want to reflect over their attributes. I do like the safety of lambdas, however, versus just typing in method name strings.)


Edit: to clarify my reasons for wanting to use Action<string>: int in my example may be any of a number of types. I tried templating that type --

void Set<T>(Func<Foo, Func<string, T>> a) { }
void Test() { Set(foo => foo.Hello); }  // fails

-- but the compiler can't derive T (presumably for the same reasons I can't overload on return type?).

Any other ideas? I'm not opposed in this case to some crazy reflection as long as I can get the compiler to check the name of that method group.


Solution

  • When it has a non-void return type, it's no longer compatible with Action<string>. In other words, this would fail too:

    int Foo(string s) { return 10; }
    
    // Error: wrong return type
    Action<string> action = new Action<string>(Foo);
    

    For the reasons why this isn't allowed, see Eric Lippert's blog post on "The void is invariant".

    You should be able to use method group syntax like this:

    public class Foo { public int Hello(string s) { return 10; } }
    
    void Test()
    {
        Func<Foo, Func<string, int>> a = foo => foo.Hello;
    }
    

    That works for me in both VS2008 and VS2010. There have been some changes to method group conversions and type inference for C# 4 - the details escape me unfortunately - but I don't believe this case is affected by those changes.