Неопределенная перегрузка универсального метода с типами, допускающими значение NULL

Скажем, у меня есть два общих перегруженных метода формы:

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);
}

Теперь, вызывая метод с переменной типа, допускающего значение NULL, C # отказывается от компиляции и сообщает, что вызов неоднозначен между двумя перегрузками:

int? maybeX = 3;
Do(maybeX, x => x.ToString());

Вызов неоднозначен для следующих методов или свойств: 'Program.Do<int?>(int?, System.Func<int?,string>)' и 'Program.Do<int>(int?, System.Func<int,string>)'

Простые исправления состоят в том, чтобы включить общий параметр при вызове метода или указать тип лямбда-аргумента:

Do<int>(maybeX, x => x.ToString());
Do(maybeX, (int x) => x.ToString());

Интересно, что выбор int? в качестве универсального типа во время вызова не будет компилироваться

Тип должен быть ссылочным типом, чтобы использовать его в качестве параметра «T» в универсальном типе или методе ».

Почему? Очевидно, только одна из двух перегрузок может использоваться со значением типа int?, но компилятор говорит, что вызов неоднозначен. Могу ли я дополнительно ограничить методы, чтобы помочь компилятору решить, какой метод вызывать, без явного указания типа в вызывающем коде?


person knittl    schedule 04.08.2015    source источник


Ответы (1)


Ограничение where T : class не является частью сигнатуры метода. Эта проверка выполняется позже в процессе выбора перегрузки метода.
Вот почему она считается неоднозначной. Оба метода совпадают до того, как будут проверены какие-либо ограничения.
Если вы явно укажете Do<int?> только первый метод является совпадением, но затем ограничение «срабатывает» и определяет, что оно недопустимо, потому что int? не является ссылочным типом.

Второй метод будет выбран, если вы измените его на:

public static string Do<T>(T? maybeValue, Func<T?, string> func)
    where T : struct
person Dennis_E    schedule 04.08.2015