【发布时间】:2011-09-14 15:18:01
【问题描述】:
我正在尝试使用以下代码:
private Nullable<List<IpAddressRange>> ipAddressRangeToBind;
但我收到以下警告:
List 类型必须是不可为空的值类型 为了将它用作泛型类型或方法中的参数“T” 'System.Nullable'。
【问题讨论】:
我正在尝试使用以下代码:
private Nullable<List<IpAddressRange>> ipAddressRangeToBind;
但我收到以下警告:
List 类型必须是不可为空的值类型 为了将它用作泛型类型或方法中的参数“T” 'System.Nullable'。
【问题讨论】:
List<T> 已经是一个引用类型(对于任何类型的T)——你只能声明Nullable<T>,其中T 是一个不可为空的值类型(它被声明为Nullable<T> where T : struct)。
不过没关系,因为如果你只是声明:
private List<IpAddressRange> ipAddressRangeToBind;
那么你还可以拥有
ipAddressRangeToBind = null;
因为引用类型总是可以为空。
【讨论】:
List<IpAddressRange> 是一个引用类型 - 它已经可以为空 - 实际上它会被该声明初始化为 null。
【讨论】:
你可以直接使用它:
List<IpAddressRange> ipAddressRangeToBind = null;
列表已经可以为空。
【讨论】:
Nullable<T> where T : struct 和 IpAddressRange 不是 struct。为什么你问的约束?这是一个不同的问题:)
由于泛型的where T : struct 约束,引用类型不能包装在Nullable<T> 中。
这个限制的原因是:
Nullable<T> 有一个布尔属性HasValue 和一个类型T 属性Value,其中包含实际的值类型值。
即使HasValue == false(也就是说,如果可以为空的包装变量设置为null),您仍然会消耗值类型的空间,就好像它在那里一样。
逻辑上可以为空以允许您指定可选行为,但它不会节省任何空间。这与 boost::optional 在 C++ 中的工作方式非常相似。
【讨论】:
Nullable<T> 的许多烦恼源于希望让它假装一个空实例是null。恕我直言,这是一个不幸的决定,因为它阻止了像 TryGetValue 这样可能有也可能没有 T 返回的方法,而不必担心 TValue 的类型而无需担心 TValue 的类型(如果 @返回项的987654335@为false,key不存在;HasValue为true,即使存储的Value恰好是null,key也存在。另一方面,虽然可空类型在逻辑上应该与其类型参数协变......
Animal? 都应该能够保存任何Cat? 的内容),使协方差在从Animal? 或Animal?? 到Object 的转换中起作用保留可空性的程度,将要求从可空类型转换为 Object 不使用正常装箱。在正常的装箱规则下,装箱的值类型总是是可变的(即使底层的值类型被认为是“不可变的”)。太糟糕了,因为这样的设计增加了使诸如“可读字典”接口之类的东西与存储在其中的值的类型相关的难度。