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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With