可为空的属性与可为空的局部变量



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

class TestClass {
    public int? value = 0;
}
TestClass test = new TestClass();

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

FieldInfo field = typeof(TestClass).GetFields(BindingFlags.Instance | BindingFlags.Public)[0];

我调用

Nullable.GetUnderlyingType(field.FieldType).ToString()

它返回一个System.Nullable[System.Int32]类型。因此,这意味着方法Nullable.GetUnderlyingType()具有不同的行为,具体取决于您获取成员类型的方式。为什么会这样?如果我只是使用test.value那么如何在不使用反射的情况下判断它是Nullable的?

> smartcaveman 的答案是迄今为止最好的答案,因为它实际上标识了描述这种行为的文档部分。

这种行为是不可取和不幸的;这是由于行为结合了三个特征,而这三个特征本身的行为是合理的。

这三个功能是:

  • GetType是一种非虚拟方法;它不能被覆盖。这应该是有道理的;对象无法决定其类型报告为什么。通过使其非虚拟,该方法可以保证说出真相。

  • 传递给在 object 上声明的非虚拟方法的this值必须转换为 object;因此,对于值类型的对象,对 GetType() 调用的接收方被装箱到 object 上。

  • 可为 null
  • 的值类型没有装箱形式;将可为 null 的 int 装箱时,要么获得带盒的 int,要么获得 null 引用。您永远不会获得对带框的可为空 int 的有效引用。

每个功能本身都是合理的,但组合起来结果是不希望的:当您在有效的可为空的 int 上调用 GetType 时,运行时会将可为空的 int 装箱到带盒的 int 中,然后将其作为object.GetTypethis传递,当然会报告int。如果该值是可为空的 int,则运行时框为 null,然后在空引用上调用 GetType 并崩溃。这两种行为都不是可取的,但我们坚持了下来。

可为空的类型有点奇怪。 但是,至少他们的行为是有据可查的。

来自 MSDN 上的 C# 编程指南,"如何:识别可为空的类型"at http://msdn.microsoft.com/en-us/library/ms366789(VS.80(.aspx :

还可以使用 System.Reflection 命名空间的类和方法来生成表示可为 Null 类型的 Type 对象。但是,如果尝试在运行时使用 GetType 方法或 is 运算符从可为 Null 的变量获取类型信息,则结果是表示基础类型的 Type 对象,而不是 Nullable 类型本身。在可为 Null 的类型上调用 GetType 会导致在类型隐式转换为 Object 时执行装箱操作。因此,GetType 始终返回一个表示基础类型的 Type 对象,而不是 Nullable 类型。

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

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

问题是你假设test.valueTypevalue field.FieldTypeType相同,但事实并非如此。 获取test.valueType实际上会获得字段中存储的内容的Type,在本例中为 0。

Type t = test.value.GetType()

与(在您的示例中(相同

Type t = 0.GetType()

为了演示,将value初始化为 null,test.value.GetType()将引发NullReferenceException

方法 GetNulllableUnderlyingType 返回 基础类型 对于可为空的类型,对于另一种类型返回 null;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetNulllableUnderlyingType(new TestClass().value));
        Console.WriteLine(GetNulllableUnderlyingType(new TestClass()));
        Console.ReadKey();
    }
    public class TestClass
    {
        public int? value;
    }
    public static Type GetNulllableUnderlyingType<T>(T value)
    {
        Type result =  Nullable.GetUnderlyingType(typeof (T));
        return result;
    }
}

首先,示例中Nullable.GetUnderlyingType(test.value)将无法编译。或者typeof(test.value)正如我在评论中看到的那样。

让我们通过以下修改后的代码来回答这个问题:

TestClass test = new TestClass();
Type type1 = test.value.GetType(); // Gets the type of the data inside the field ==> System.Int32.
Type underlyingType1 = Nullable.GetUnderlyingType(type1); // Gets the underlying type of System.Int32 ==> null.
FieldInfo field = typeof(TestClass).GetFields(BindingFlags.Instance | BindingFlags.Public)[0];
Type type2 = field.FieldType; // Now the type is retrieved of the field, not the data inside. ==> System.Int32?
Type underlyingType2 = Nullable.GetUnderlyingType(type2); // Gets the underlying type of System.Int32? ==> System.Int32.

当您对字段执行GetType()时,您将获得内部数据类型,而不是字段本身的类型。例如:

object o = 1;
Type type = o.GetType();

在此示例中,当您调用 GetType() 时,您还将得到 System.Int32 ,而不是 System.Object 。因为在调用GetUnderylingType之前,您从不同类型的开始,最终会得到不同的结果。

相关内容

  • 没有找到相关文章

最新更新