Generic Method Resolution - c#

Consider the following code:
public class Tests
{
public void Test()
{
Assert.AreEqual("Int", DoSomething(1));
}
public static string DoSomething<T>(T value)
{
return "Generic";
}
public static string DoSomething(int value)
{
return "Int";
}
}
As expected, the non-generic DoSomething method will be invoked. Now consider the following modification:
public class Tests
{
public void Test()
{
Assert.AreEqual("Int", DoSomething(1));
}
public static string DoSomething<T>(T value)
{
return "Generic";
}
public static string DoSomething<T>(int value)
{
return "Int";
}
}
The only thing I've changed is adding the T type parameter to the second overload, thus making it generic. Note that the type parameter is not used.
That modification causes the first DoSomething method to be called. Why? The compiler has all the information it needs in order to choose the second method.
Can you please explain why, or even better, point me to the section of the C# specification that explains this behavior?

In your call, you're not specifying a type argument - so the compiler would have to infer the type of T. It can't do that for your second method, because the type parameter is never mentioned in the declared parameters. Therefore, that overload is not applicable, and is ignored.
If you specify a type argument to the call, e.g. any of
DoSomething<int>(1)
DoSomething<object>(1)
DoSomething<string>(1)
... then in all cases the second overload will be called.
From section 7.6.5.1 of the C# 5 spec, (method invocations) when constructing the set of candidate methods:
If F is generic and M has no type argument list, F is a candidate when:
Type inference (§7.5.2) succeeds, inferring a list of type arguments for the call, and
Once the inferred type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (§4.4.4), and the parameter list of F is applicable with respect to A (§7.5.3.1).
As type inference doesn't succeed, the second method isn't in the candidate set, so by the time we get to real overload resolution, the set just has a single method in (the first one).

the compiler can not determine the type of pattern in the call DoSomething(1), but if you specify [int] it will be selected another method.

Related

The return type / return value is part of the signature of the method?

C# documentation Methods states
Methods are declared in a class, struct, or interface by specifying
the access level such as public or private, optional modifiers such as
abstract or sealed, the return value, the name of the method, and any
method parameters. These parts together are the signature of the
method.
public class Foo
{
public int InstanceMethod1()
{
return 85;
}
public static string StaticMethod1()
{
return "Bar";
}
}
In regards to the above excerpt, by "return value" is it referring to the "return type" of the method? Thus, the return type of a method (in the above examples int and string) is considered part of the signature of the method?
Note, I did read following side note "A return type of a method is not part of the signature of the method for the purposes of method overloading. However, it is part of the signature of the method when determining the compatibility between a delegate and the method that it points to."... However, my above example has nothing to do with method overloading.
The return value of a method must strictly follow the return type of its method so you could technically use the two terms interchangeably when talking about method signatures which it looks like they've done in the excerpt, albeit confusing.
In the case of method overloading the return type is not considered part of the method signature as the compiler cannot determine on return type alone which methods to use and as such the return type is not included in the method signature. For example consider the following overloaded methods where only the return type differs:
public int GetResult() { }
public double GetResult() { }
If we were to call this method, how would the compiler know which method to use?
var result = GetResult();
However as the language definition states: the method name, number of generic types, number of and type of each formal parameter and out/ref/value parameters are part of the method signature when overloading so for example if you wanted to overload then you could do:
public int GetResult() { }
public int GetResult(int x) { }
There are cases where the return type of a method is considered part of the signature such as delegates since the method must have the same return type as the delegate declaration. As per the C# specification:
In the context of method overloading, the signature of a method does not include the return value. But in the context of delegates, the signature does include the return value. In other words, a method must have the same return type as the delegate.

Generic method overload ambiguous with nullable types

Say I have two generic, overloaded methods of the form:
public string Do<T>(T maybeValue, Func<T, string> func)
where T : class
{
if(maybeValue == null) return null;
return func(maybeValue);
}
public string Do<T>(T? maybeValue, Func<T, string> func)
where T : struct
{
if(!maybeValue.HasValue) return null;
return func(maybeValue.Value);
}
Now, calling the method with a variable of type nullable, C# refuses to compile and says that the call is ambiguous between the two overloads:
int? maybeX = 3;
Do(maybeX, x => x.ToString());
The call is ambiguous between the following methods or properties:
'Program.Do<int?>(int?, System.Func<int?,string>)' and
'Program.Do<int>(int?, System.Func<int,string>)'
Easy fixes are to include the generic parameter when calling the method, or to specify the type of the lambda argument:
Do<int>(maybeX, x => x.ToString());
Do(maybeX, (int x) => x.ToString());
Interestingely, choosing int? as generic type during invocation will not compile
The type must be a reference type in order to use it as parameter 'T' in the generic type or method".
How come? Obviously only one of the two overloads can be used with a value of type int?, yet the compiler says the call is ambiguous. Can I further constrain the methods to help the compiler decide which method to call, without having the invoking code specify the type explicitely?
The where T : class constraint is not part of the signature of the method. That check happens later in the method overload selection process.
That's why it is considered ambiguous. Both methods are a match before any constraints are checked.
If you explicitly say Do<int?> only the first method is a match, but then the constraint 'kicks in' and determines it is invalid because int? is not a reference type.
The second method will be chosen if you change it to:
public static string Do<T>(T? maybeValue, Func<T?, string> func)
where T : struct

Ambiguous method call with Action<T> parameter overload

I encountered some unexpected compiler behaviour when calling overloaded method with different Action<T> variations.
Let's say I have this class Test and I'm creating its instance in the CallTest constructor.
public class Test
{
public Test(Action<long> arg)
{
}
public Test(Action<decimal> arg)
{
}
}
public class CallTest
{
public CallTest()
{
Test t = new Test(TestDecimal);
}
public void TestDecimal(decimal arg)
{
}
public void TestLong(long arg)
{
}
}
When calling the Test constructor with either TestDecimal or TestLong as a parameter I'm receiving the following error:
The call is ambiguous between the following methods or properties: 'Test(System.Action<long>)' and 'Test(System.Action<decimal>)'
My guess is there's some implicit conversion going on between long and decimal, but does anyone have any other idea what could have I done wrong? Is there any workaround?
When you pass TestDecimal or TestLong as a parameter you're in fact passing a method group (after all, there could be more than one TestDecimal method - it could have been overloaded). So in both cases implicit conversion occurs - from a method group to a particular delegate type. Both methods are thus applicable candidates (Section 7.4.2). From applicable candidates the overload resolution algorithm tries to find the best candidate. However, the rules of comparing conversions when matching parameter lists state, that if for both candidates implicit conversion occurs neither of them is better:
Section 7.4.2.3:
[...]
Otherwise, neither conversion is better.
That's why in your case there is an ambiguity.
The workaround is of course to first cast the parameter explicitly:
new Test(new Action<decimal>(TestDecimal))
This way for one case there will be no need for implicit conversion during overload resolution (as after the cast Action<T> type will match exactly), and the other would have to be converted (Action<long> to Action<decimal>), and the section mentioned above states that:
[...]
If S is T1, C1 is the better conversion.
If S is T2, C2 is the better conversion.
[...]
There is a workaround:
Test t = new Test(new Action<decimal>(TestDecimal));
This is due to an implicit casting between long and decimal.
Here's a table of implicit castings(for simple types) in C#(Picture Source):
Read more about type conversions here.

Pass arbitrary actions to the same method

Why is the following call ambiguous:
public class Foo
{
public void Bar<T> (Action<T> simple);
public void Bar<T1, T2> (Action<T1, T2> complex);
}
...
public class Test
{
public static void MyComplex (string a, string b) { ... }
}
...
foo.Bar(Test.MyComplex);
Shouldn't it be clear to the compiler to call the Bar<T1,T2>() method?
If you remove this method public void Bar<T> (Action<T> simple);, your code just will not compile, because you get this exception:
The type arguments for method 'Foo.Bar(System.Action)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
Unfortunately the compiler can not get types from this method, and you should write this code to call method:
new Foo().Bar(new Action<string, string>(Test.MyComplex));
The compiler is trying to infer the generic parameter types for Bar but to do that it needs to know all the argument types. The argument you have (Test.MyComplex) is actually method group, not a delegate so the compiler is also required to insert a conversion to a compatible delegate type. However it can't because it does not know the what delegate types to use because type inference on the method it needs to be compatible with has not completed yet. There's a chicken-and-egg problem and the compiler gives up saying the call is ambiguous. Eric Lippert points out in the comments to a very similar question that in simple cases like this, it could be worked out but at the expense of complicating the overload resolution rules.
Unfortunately you are required to do something that gives the compiler more information:
foo.Bar<string, string>(Test.MyComplex);
or
Action<string, string> action = Test.MyComplex;
foo.Bar(action);

How to dispatch C# generic method call into specialized method calls

I have the following C# class:
public class MyType<T>
{
public void TryParse(string p_value)
{
T value ;
Parser.TryParse(p_value, out value);
// Do something with value
}
}
The point is to call the right Parser.TryParse method, depending on the generic type T.
This uses the following static class:
static public class Parser
{
static public void TryParse(string p_intput, out object p_output)
{
// Do something and return the right value
}
static public void TryParse(string p_intput, out double p_output)
{
// Do something and return the right value
}
static public void TryParse(string p_intput, out int p_output)
{
// Do something and return the right value
}
}
I expected this to work: In the worst case, the "object" TryParse would be called. Instead, I have two compilation errors:
CS1502: The best overloaded method match for 'Parser.TryParse(string, out object)' has some invalid arguments
CS1503: Argument 2: cannot convert from 'out T' to 'out object'
Question 1: I don't understand why this doesn't work: I can be naive, but aren't all C# objects supposed to derive from "object" ? Why T cannot be converted to object?
Question 2: How can I dispatch a method with generic type T into the right non-generic methods (i.e. MyType<T>.TryParse calling the right Parser.TryParse according to the right type of T) ?
Note
The question was edited to reflect the original question intent (as written in the title: How to dispatch C# generic method call into specialized method calls)
Actually, ref and out parameters do not allow type variation. So, to pass a variable to a method expecting an out object parameter, that variable must be declared as object.
From the specification (§10.6.1.2 and §10.6.1.3)
When a formal parameter is a reference parameter, the corresponding argument in a method invocation must consist of the keyword ref followed by a variable-reference (§5.3.3) of the same type as the formal parameter.
When a formal parameter is an output parameter, the corresponding argument in a method invocation must consist of the keyword out followed by a variable-reference (§5.3.3) of the same type as the formal parameter.
See: Why do ref and out parameters not allow type variation? for some insight into why.
Bonus question: How can I dispatch a method with generic type T into the right non-generic methods (i.e. MyType<T>.TryParse calling the right Parser.TryParse according to the right type of T)?
I'm going to turn it back around on you. Why are you doing this? If you are invoking MyType<T>.TryParse as, say, MyType<int>.TryParse, why not call Int32.TryParse directly? What is this extra layer buying you?
I know this is somewhat low-tech, but I have had the same problem, where I solved it by making a Dictionary<Type, Parser> containing the individual parsers. I will be interested in what answers this questions bring.
Regards,
Morten
Current solution
The current solution I use at work is based on dynamic dispatch, that is, the keyword dynamic as defined on C# 4.0.
The code is something like (from memory) :
public class Parser
{
static public void TryParse<T>(string p_input, out T p_output)
{
// Because m_p is dynamic, the function to be called will
// be resolved at runtime, after T is known...
m_p.DoTryParse(p_input, out p_output) ;
}
// The dynamic keyword means every function called through
// m_p will be resolved at runtime, at the moment of the call
private dynamic m_p = new Parser() ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
private void DoTryParse(string p_input, out double p_output)
{ /* Do something and return the right value */ }
private void DoTryParse(string p_input, out int p_output)
{ /* Do something and return the right value */ }
// etc.
private void DoTryParse<T>(string p_input, out T p_output)
{
// fallback method... There are no dedicated method for T,
// so p_output becomes the default value for T
p_output = default(T) ;
}
}
The elegant part is that it can't fail (the fallback function will be called, if none with a better signature match is found), and that it follows a simple pattern (overload the function).
Of course, the real-life, production code is somewhat different, and more complicated because, with but one public static method, I want to :
parse both reference objects (classes) and value objects (structs)
parse enums
parse nullable types
I want to offer the user the possibility to derive from Parser to offer its own overloads in addition to the default ones
But I guess the use of dynamic in the current solution is, in the end, the same thing as doing reflection as done in the original answer below. Only the "notation" changes.
Conclusion, I now have the following method :
public class Parser
{
static public void TryParse<T>(string p_input, out T p_output)
{
// etc.
}
}
which is able to parse anything, including in situations where T is not known at compile time (because the code is generic).
Original answer
Jason's answer was right about the first question (about the compiler errors). Still, I had no solution to my problem (dispatching from a generic method to non-generic methods according to the runtime generic type T).
I tried LukeH's answer, but it didn't work: The generic method is always called, no matter what (even when removing the out qualifier of the second parameter).
Morten's answer is the most sane one that should works, but it doesn't make use of reflection.
So, to solve my own problem, I used reflection. This needs the rewriting of the generic TryParse method:
public class MyType<T>
{
public void TryParse(string p_value)
{
T value = default(T);
// search for the method using reflection
System.Reflection.MethodInfo methodInfo = typeof(Parser).GetMethod
(
"TryParse",
new System.Type[] { typeof(string), typeof(T).MakeByRefType() }
);
if (methodInfo != null)
{
// the method does exist, so we can now call it
var parameters = new object[] { p_value, value };
methodInfo.Invoke(null, parameters);
value = (T)parameters[1];
}
else
{
// The method does not exist. Handle that case
}
}
}
I have the source code available if needed.
This problem intrigued me, so I did some research and found a nice thing by Paul Madox. This seems to do the trick.
public static T SafeParseAndAssign<T>(string val) where T: new()
{
try
{
T ValOut = new T();
MethodInfo MI = ValOut.GetType().
GetMethod("Parse", new Type[] { val.GetType() });
return (T)MI.Invoke(ValOut, new object[] { val });
}
catch
{
// swallow exception
}
return default(T);
}

Categories