Вне параметров с обнуляемыми ссылочными типами
Я реализовал Option
напишите для какого-нибудь моего проекта:
public abstract Option<T> {}
public class None<T> : Option<T>
public class Some<T> : Option<T>
{
public T Value { get; }
public Some(T value)
{
Value = value;
}
}
Чтобы выяснить, содержит ли Option значение, я использую этот метод расширения, который использует сопоставление с образцом:
public static bool TryGetValue<T>(this Option<T> option, out T value)
{
if (option is Some<T> some)
{
value = some.Value;
return true;
}
value = default;
return false;
}
Теперь я получаю следующее предупреждение для return default;
Невозможно преобразовать нулевой литерал в необнуляемую ссылку или параметр неограниченного типа
Для меня невозможно ограничить общий параметр T
в class
или же struct
,
Например, если я ограничил универсальный параметр class
Я не мог генерировать Option<int?>
случаи как Nullable<int>
тип является struct
сам. Объявление параметра out как обнуляемого через постфикс ?
это тоже не решение, как кажется.
Для меня система типов на данном этапе несколько сломана или недостаточно продумана. Либо Nullable должен был быть class
или должно быть ограничение общего параметра, например:
public static bool TryGetValue<T>(this Option<T> option, out T value)
where T : nullable [...]
Есть ли другой подход, который может подойти для этой проблемы? Что мне не хватает?
0 ответов
Если вы просто хотите получить это для компиляции, то вы можете использовать !
оператор:
public static bool TryGetValue<T>(this Option<T> option, out T value)
{
if (option is Some<T> some)
{
value = some.Value;
return true;
}
value = default!;
return false;
}
К сожалению, это будет означать, что T не равно нулю, даже когда это может быть.
Однако, если вы убедитесь, что вы всегда используете шаблон Try правильно (т.е. проверьте возвращаемое значение TryGetValue
перед использованием параметра out) вы никогда не увидите, что это значение будет нулевым (если только T не является на самом деле обнуляемым типом, в этом случае вы все равно в порядке).
На сегодняшний день нет удобного способа получить полностью универсальное решение с C# 8.0.
[NotNullWhen()]
attribute - это шаг вперед, но тогда мы столкнемся со следующим:
Параметр типа, допускающий значение NULL, должен быть известен как тип значения или ссылочный тип, не допускающий значения NULL. Рассмотрите возможность добавления ограничения типа, структуры или типа.
Я бы сказал, что сейчас это основная проблема с нулевыми значениями. Надеюсь, это будет решено в 8.1 или что-то в этом роде...
Соответствующее обсуждение - https://github.com/dotnet/csharplang/issues/2194 - разрешить универсальным методам указывать T? без ограничения классом или структурой.
В качестве обходного пути несколько копий метода расширения с требуемым where
могут быть наложены ограничения, охватывающие все возможные типы.
Поскольку проблема №1628 была исправлена, теперь можно иметь все перегрузки в одном классе расширения. Но по-прежнему требуется удвоить количество методов расширения для каждого независимого универсального выходного параметра. Ой!
Беглый взгляд, я не смог найти открытую проблему, специфичную для выходных параметров. Возможно, стоит перенести этот конкретный вариант использования на проблемы csharplang github, если это еще не сделано.
Обновление: я прокомментировал вышеупомянутую проблему со своим мнением.