Почему 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> с момента его получения).