根本原因/问题是,CLS规范的设计者(定义了语言与.net的交互方式)没有定义类成员可以指定必须直接调用而不是通过它们调用的方法。callvirt
,而不由调用者执行空引用检查;它也没有提供定义不会受到“正常”拳击的结构的手段。
如果CLS规范定义了这样一种方法,则.net可以始终遵循公共对象模型(COM)建立的引导,在这种引导下,空字符串引用在语义上等效于空字符串,对于其他用户定义的不可变类类型,应该具有值语义来同样定义默认值。本质上,将对的每个成员发生什么事String
,例如Length
写成[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
。这种方法本来可以为应该像值一样表现的事物提供非常好的语义,但是由于实现问题,需要将其存储在堆中。这种方法最大的困难在于,此类类型和Object
可能会有些模糊。
一种替代方法是允许定义特殊结构类型,这些特殊结构类型不继承自Object
而是具有自定义装箱和拆箱操作(这将与其他类类型相互转换)。在这种方法下,将有一个类类型NullableString
,其行为现在类似于字符串,还有一个自定义框结构类型String
,该类型将容纳一个Value
type的私有字段String
。如果非null或null,则尝试将转换String
为NullableString
或Object
将返回。尝试强制转换为,实例的非null引用会将引用存储在Value
String.Empty
String
NullableString
Value
(如果长度为零,则可能存储null);投射任何其他引用都将引发异常。
即使字符串必须存储在堆中,从概念上讲,也没有理由不使它们的行为不像具有非空默认值的值类型。将它们存储为包含引用的“常规”结构对于使用它们作为“字符串”类型的代码本来是有效的,但是当强制转换为“对象”时会增加一层间接性和无效性。尽管我不希望.net在今天晚些时候添加上述任何一项功能,但也许未来框架的设计人员可能会考虑将它们包括在内。