Почему Nullable считается структурой, а не классом?
Я пытаюсь определить общий класс, который принимает любой тип, который может быть установлен в null:
public abstract class BundledValue_Classes<T>
where T : class
{
private Tuple<T, object> _bundle= new Tuple<T, object>();
public T Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, obj); }
}
//...
это прекрасно работает. Я также хочу создать производный класс, который может принимать любой примитивный тип (int, double и т. д.) и просто разрешать это в то же самое, что и вышеупомянутый класс, но где примитив обернут в Nullable
public abstract class BundledValue_Structs<T>
: BundledValue_Classes<T?>
where T : struct
{
//...
}
но по какой-то причине, это не работает. Я получаю сообщение об ошибке:The type 'T?' must be a reference type in order to use it as parameter 'T' in the generic type or method 'BundledValue_Classes<T>'
понятно ли, что я пытаюсь здесь сделать? Я не хочу для того, чтобы скопировать вставить содержимое целого BundledValue_Classes<T>
класс просто для обработки случая примитива, завернутого в Nullable<T>
.
возможно, есть какой-то способ установить ограничения типа BundledValue_Classes<T>
чтобы он принимал не только классы, но и любой тип, которому может быть присвоено нулевое значение (включая Nullable<T>
типы, которые кажутся единственным исключением из правила.)
2 ответов
Nullable<T>
и структура согласно документации. Это просто не класс. Это тип значения, который выглядит немного так с точки зрения полей:
public struct Nullable<T>
{
private readonly T value;
private readonly bool hasValue;
}
на null
значение Nullable<T>
type не является нулевой ссылкой, Это просто значение, где hasValue
поле false.
отметим, что Nullable<T>
не удовлетворяет условию ограничения where TFoo : struct
однако, как это на самом деле необнуляемый тип значения ограничение. В основном Nullable<T>
не удовлетворяет ни class
или struct
ограничения. Нет никакого ограничения, которое тут разрешить только для типов nullable (ссылка или Nullable<T>
).
как уже отмечалось, тип Nullable<T>
является структурой, которая инкапсулирует T
и флаг, который указывает, является ли он допустимым. Поскольку разработчики .NET не видели никакой пользы в возможности иметь тип, который мог бы инкапсулировать вещь любой вещи и указать, является ли она действительной, они решили, что они не хотят разрешать Nullable<Nullable<T>>
[решение мне не нравится, кстати], и вместо того, чтобы придумать специальное ограничение только на общий параметр Nullable<T>
, Они решили, что хотя Nullable<T>
является структурой, она не должна удовлетворять struct
ограничение типа.
лично я предпочел бы видеть Nullable<T>
либо просто быть "обычной" структурой с открытыми полями типа bool
и без ограничений T
, который может быть использован, например,Dictionary.TryGetValue
чтобы вернуть значение и указать, действительно ли оно (независимо от того,TValue
был классом, ненулевой структурой или Nullable<T>
), или же это класс, содержащий T
. Ценность способности скажи someNullable != null
как ярлык является незначительным по сравнению с путаницей и осложнениями, которые он вызывает по сравнению с someNullable.HasValue
. До сих пор, .Сетка есть, то есть. Лично я бы предложил вообще избегать типов с нулевым значением, так как с типом с нулевым значением ничего нельзя сделать, не скопировав сначала значение. Такие типы также имеют некоторые странные причуды в отношении безопасности потоков (например, код, который получает Nullable<T>
и отмечает, что HasValue
не могу с уверенностью предположить, что GetValueOrDefault
вернутся Default(T)
, даже если ничто не могло изменить Nullable<T>
с момента его получения).