ниже приведен код, который представляет то, что я пытаюсь сделать:
private T? SomeMethod<T>(T prm)
{
if (someCondition)
return prm;
return null;
}
Итак, идея такая: метод получает параметр, имеющий значение (не null), но возвращаемое значение метода может быть как значением, так и null.
Приведенный выше код не компилируется с сообщением «Невозможно преобразовать значение null в параметр типа 'T». Если я добавлю ограничение (где T: class или где T: struct), то он скомпилируется, но я не могу этого сделать, поскольку T может быть одновременно структурой и классом.
Итак, возможно ли это с C#?
Забавно, но для меня ошибка компилятора: «Невозможно преобразовать значение null в параметр типа «T», поскольку это может быть тип значения, не допускающий значения NULL. Вместо этого рассмотрите возможность использования «default (T)».
«но я не могу этого сделать, поскольку T может быть и структурой, и классом» — как вы предлагаете создать нулевую структуру? Или вы надеетесь, что компилятор будет по-разному расширять ваш универсальный код, чтобы возвращать тип значения, допускающий значение Null, или ссылочный тип null?





Вы можете использовать default:
public T? SomeMethod<T>(T prm)
{
// ...
return default;
}
Но есть еще одна ошибка, о которой вам следует знать: для неограниченных универсальных параметров, если T является типом значения, тогда T и T? будут совпадать, т. е. SomeMethod<int> вернет int, а не int?, а для SomeMethod<int?> он вернет int? (см. этот ответ Больше подробностей). Существует немного грязный/хакерский способ решения этой проблемы — создайте 2 разных метода с параметрами по умолчанию и ограничьте их struct/class:
public T? SomeMethod<T>(T prm, T? _ = null) where T : struct
{
// ...
return default;
}
public T? SomeMethod<T>(T prm, T? _ = null) where T : class
{
// ...
return default;
}
Который будет правильно работать как для значений, так и для ссылочных типов и предотвратит/предупреждит передачу аналогов с нулевым значением (т. е. SomeMethod<int> вернет int?, а SomeMethod<int?> не скомпилирует).
Спасибо, теперь я лучше понимаю, как это работает.
defaultработает?