Overload Exceeded between Expression <Action> and Expression <Action <T>>
Short version:
What is the best way to overload two methods when one accepts Expression<Action> and the other accepts Expression<Action<T>> ?
Longer version:
Let's say I have the following methods in a (poorly 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, perhaps I am particularly dimming, but I would expect Method 2 to be called by the Main method.
The only limitation on this is that I need to pass Expression<...> , since we are doing some kind of magic elsewhere based on the expression tree.
My rationale is something like this:
- Generics aren't real - it's a compiler trick
- An
Action<T>is actually a completely different delegate type forAction - Therefore, you should call method 2, since the compiler has all the information it needs to make a conclusion.
What actually happens is that I get a compiler error, that I am trying to pass an argument to Action that takes no arguments ... i.e. Method 1 .
In a side note, this works as expected if I specify the general parameter explicitly as follows:
Foo<String>(t => Bar(t)); Your thoughts on this will be appreciated!
Currently, none of your methods are applicable - since type inference cannot infer T for your second method, and the first method is invalid because your anonymous function has a parameter (unlike Action ). The compiler reports the error as if it were performing overload resolution and chose the first method, but this is one of those cases where the error message does not actually tell the whole story.
If you change the signature of method 1 to:
Foo(Expression<Action> action, string item) and method signature 2:
Foo<T>(Expression<Action<T>> action, T item) then type inference will be executed, and the second method will be called (since the first method is not applicable).
If both methods were applicable (for example, after the aforementioned change, you changed the first parameter of the non-native method to Expression<Action<string>> ), it will fall into a tie-break in terms of normal conversions "argument to parameter type" - but then the first rule is Break (in section 7.5.3.2 of the C # 5 specification):
- If M P is an unrelated method, and M Q is a general method, then M P is better than M Qsub>.
In other words, generic methods are preferred for generic methods when overload resolution is enabled.
In terms of fixing your current code, it's hard to figure out how to do this without having more context of what you are trying to achieve.