What is the best way of overloading two methods, when one accepts an Expression<Action>
, and another accepts an Expression<Action<T>>
?
Let's say I have the following methods in a (badly designed) class:
void Main()
{
Foo(t => Bar(t));
}
void Foo(Expression<Action> action)
{
"Method 1!".Dump();
}
void Foo<T>(Expression<Action<T>> action)
{
"Method 2!".Dump();
}
void Bar(String thing)
{
// Some bar-like thing
}
Now, it may be me being particularly dim, but I would expect 'Method 2' to be invoked from the Main
method.
The only constraint on this is that I need to pass an Expression<...>
as we do some magic elsewhere based on the expression tree.
My rationale is something like this:
Action<T>
is actually a very different delegate type to an Action
What actually happens is that I get a compiler error to the effect that I'm trying to pass an argument to an Action which accepts no arguments... ie. Method 1
is being targeted.
On a side note, this works as expected if I specify the generic parameter explicitly like this:
Foo<String>(t => Bar(t));
Your thoughts on this would be appreciated!
Currently, neither of your methods is applicable - because type inference can't infer T
for your second method, and the first method is invalid because your anonymous function has a parameter (unlike Action
). The compiler is reporting an error as if it had performed overload resolution and picked the first method, but it's one of those cases where the error message doesn't really tell the whole story.
If you change the signature of method 1 to:
Foo(Expression<Action> action, string item)
and the signature of method 2 to:
Foo<T>(Expression<Action<T>> action, T item)
then type inference would work, and the second method would be invoked (as the first method isn't applicable).
If both methods were applicable (e.g. after the above change, you changed the first parameter of the nongeneric method to Expression<Action<string>>
), it would end up in a tie-break in terms of normal "argument to parameter type" conversions - but then the first tie-break rule (in section 7.5.3.2 of the C# 5 specification) is:
- If MP is a nongeneric method and MQ is a generic method, then MP is better than MQ.
In other words, non-generic methods are favoured over generic ones, in overload resolution.
In terms of fixing your current code - it's hard to know how to do that without having more context of what you're trying to achieve.
See more on this question at Stackoverflow