可空属性与Nullable局部变量

nic*_*hev 6 c# reflection nullable

我对以下Nullable类型的行为感到困惑:

class TestClass {
    public int? value = 0;
}

TestClass test = new TestClass();
Run Code Online (Sandbox Code Playgroud)

现在,Nullable.GetUnderlyingType(test.value)返回基础Nullable类型,即int.但是,如果我尝试获得这样的字段类型

FieldInfo field = typeof(TestClass).GetFields(BindingFlags.Instance | BindingFlags.Public)[0];
Run Code Online (Sandbox Code Playgroud)

我援引

Nullable.GetUnderlyingType(field.FieldType).ToString()
Run Code Online (Sandbox Code Playgroud)

它返回一个System.Nullable[System.Int32]类型.因此,这意味着该方法Nullable.GetUnderlyingType()具有不同的行为,具体取决于您获取成员类型的方式.为什么会这样?如果我只是使用我test.value怎么能告诉它Nullable没有使用反射?

Eri*_*ert 11

smartcaveman的答案是迄今为止最好的答案,它实际上标识了描述此行为的文档部分.

这种行为是不可取的,也是不幸的; 这是由于三种特征相结合的行为,它们本身表现得相当合理.

这三个功能是:

  • GetType是一种非虚方法; 它不能被覆盖.这应该是有道理的; 对象无法确定报告的类型.通过使其成为非虚拟,该方法可以保证说实话.

  • this传递给声明的非虚方法的值object必须转换为object; 因此,对于有价值类型的对象,调用的接收者GetType()被加框object.

  • 可以为空的值类型没有盒装形式; 当你打开一个可以为空的int时,你得到一个盒装的int或者你得到一个空引用.您永远不会获得对盒装可空int的有效引用.

每个特性本身都是合理的,但结合起来是不可取的:当你调用GetType一个有效的可空int时,运行时将nullable int打包到一个盒装的int然后传递给当然报告thisobject.GetType那个int.如果该值为null nullable int,则运行时框为null,然后GetType在空引用上调用并崩溃.这些行为都不可取,但我们坚持使用它们.

  • 问题本质上是"默认"意味着"如何通过内存分配器初始化此类型的字段或数组元素",这实际上不是*语义*默认值. (2认同)

sma*_*man 8

可空类型有点奇怪.但是,至少他们的行为有很好的记录.

从MSDN上的C#编程指南,"如何:识别可空类型",请访问http://msdn.microsoft.com/en-us/library/ms366789(VS.80).aspx:

您还可以使用System.Reflection命名空间的类和方法来生成表示Nullable类型的Type对象.但是,如果尝试使用GetType方法或is运算符在运行时从Nullable变量获取类型信息,则结果是一个Type对象,它表示基础类型,而不是Nullable类型本身.

在Nullable类型上调用GetType会导致在将类型隐式转换为Object时执行装箱操作.因此,GetType始终返回表示基础类型的Type对象,而不是Nullable类型.

值得指出的是,标题中的区别是不准确的.类型行为不是基于局部变量或属性,而是基于是通过运行时对象还是通过反射(或使用typeof运算符)来访问类型.你的推理是可以理解的,因为局部变量的类型通常只能通过运行时对象访问,但是它有缺陷,因为如果你在运行时通过属性访问器访问一个可空对象,那么它的行为将等同于一个局部变量.

另外,要明确回答问题的最后一部分:告诉test.value在没有使用反射的情况下可以为空的唯一方法是访问它并获得NullReferenceException(当然,只有当test.value为null时才会发生这种情况)如上所述,在您的示例中,该值不为null,因此无需反射就可以确定此值