Обнуляемые ссылочные типы с универсальным типом возврата - PullRequest
0 голосов
/ 08 февраля 2019

Я немного поигрался с новой функцией C # 8 для обнуляемых ссылочных типов, и во время рефакторинга своего кода я наткнулся на этот (упрощенный) метод:

public T Get<T>(string key)
{
    var wrapper = cacheService.Get(key);
    return wrapper.HasValue ? Deserialize<T>(wrapper) : default;
}

Теперь это дает предупреждение Possible null reference return, что логично, так как default(T) даст ноль для всех ссылочных типов.Сначала я подумал, что смогу изменить это на следующее:

public T? Get<T>(string key)

Но это невозможно сделать.Там написано, что я должен добавить общее ограничение where T : class или where T : struct.Но это не вариант, так как это может быть и другое (я могу сохранить int или int? или экземпляр FooBar или что-то еще в кэше).Я также читал о предполагаемом новом обобщенном ограничении where class?, но, похоже, оно не сработало.

Единственное простое решение, о котором я могу подумать, - это изменение оператора возврата с помощью оператора нулевого прощения :

return wrapper.HasValue ? Deserialize<T>(wrapper) : default!;

Но это неправильно, так как он определенно может быть нулевым, так что я в основном здесь вру компилятору: -)

Как это исправить?Я что-то упускаю здесь совершенно очевидно?

1 Ответ

0 голосов
/ 08 февраля 2019

Я думаю, default! - лучшее, что вы можете сделать на данный момент.

Причина, по которой public T? Get<T>(string key) не работает, заключается в том, что ссылочные типы, допускающие значение NULL, очень отличаются от значения NULL.типы значений.

Обнуляемые ссылочные типы - это просто время компиляции.Маленькие вопросительные и восклицательные знаки используются только компилятором для проверки возможных нулей.С точки зрения среды выполнения, string? и string абсолютно одинаковы.

Типы значений, допускающие значение Nullable, с другой стороны, являются синтаксическим сахаром для Nullable<T>.Когда компилятор компилирует ваш метод, он должен определить тип возврата вашего метода.Если T является ссылочным типом, ваш метод будет иметь тип возвращаемого значения T.Если T является типом значения, ваш метод будет иметь тип возвращаемого значения Nullable<T>.Но компилятор не знает, как с этим справиться, когда T может быть и тем, и другим.Конечно, нельзя сказать, что «тип возвращаемого значения T, если T является ссылочным типом, и Nullable<T>, если T является ссылочным типом».потому что CLR не поймет этого.Метод должен иметь только один тип возвращаемого значения.

Другими словами, сказать, что вы хотите вернуть T?, все равно, что сказать, что вы хотите вернуть T, когда T является ссылочным типом и возвращает Nullable<T>, когда T является типом значения.Это не похоже на допустимый тип возвращаемого значения для метода, не так ли?

В качестве действительно плохого обходного пути вы можете объявить два метода с разными именами - один имеет T, ограниченный типами значений, идля других T ограничен ссылочными типами.

...