为什么Nullable <t>被认为是结构而不是类?</t>

时间:2013-12-14 21:57:55

标签: c# generics nullable type-constraints

我正在尝试定义一个泛型类,它接受任何可以设置为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>上设置类型约束,这样它就不仅可以接受类,还可以接受任何可以赋值为null的类型(包括Nullable<T>类型,看起来像规则的唯一例外。)

2 个答案:

答案 0 :(得分:15)

Nullable<T> 结构as per the documentation。它根本不是一个阶级。它是一种值类型,在字段方面看起来有点像这样:

public struct Nullable<T>
{
    private readonly T value;
    private readonly bool hasValue;
}

null类型的Nullable<T>值不是空引用,它只是hasValue字段为false的值。

请注意,Nullable<T>不满足约束where TFoo : struct的条件,因为它实际上是不可为空的值类型约束。基本上Nullable<T>不满足classstruct约束。 只允许可以为空的类型(引用或Nullable<T>)没有约束。

答案 1 :(得分:0)

如上所述,类型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>。 .NET仍然是它的本质。就个人而言,我建议一般避免使用可空类型,因为在没有首先复制值的情况下,可以使用可空类型做任何事情。这些类型在线程安全方面也存在一些奇怪的怪癖(例如,接收HasValue的代码并观察到GetValueOrDefault无法安全地假设Default(T)将返回Nullable<T>,即使自收到以来,没有任何东西可以修改{{1}}。