Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 797
knittl Avatar asked Aug 04 '15 07:08

knittl


1 Answers

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
like image 177
Dennis_E Avatar answered Sep 28 '22 22:09

Dennis_E