Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 可空属性与可空局部变量_C#_Reflection_Nullable - Fatal编程技术网

C# 可空属性与可空局部变量

C# 可空属性与可空局部变量,c#,reflection,nullable,C#,Reflection,Nullable,我对Nullable类型的以下行为感到困惑: class TestClass { public int? value = 0; } TestClass test = new TestClass(); 现在,Nullable.getunderyingtype(test.value)返回底层Nullable类型,即int。 但是,如果我试图获得这样的字段类型 FieldInfo field = typeof(TestClass).GetFields(BindingFlags.Instan

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

class TestClass {
    public int? value = 0;
}

TestClass test = new TestClass();
现在,
Nullable.getunderyingtype(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
如何在不使用反射的情况下判断它是
可空的
问题在于,您假设
test.value
类型与
字段的
类型相同,而
value
字段类型与
字段类型相同。获取
测试的
类型
。值
实际上获取字段中存储内容的
类型
,在本例中为0

Type t=test.value.GetType()

(在您的示例中)与

Type t=0.GetType()


为了演示,将
value
初始化为null,并
test.value.GetType()
将抛出
NullReferenceException

可为null的类型有点奇怪。然而,至少他们的行为是有据可查的

从MSDN的C#编程指南中, “如何:标识可为空的类型”地址:

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

对可为null的类型调用GetType会导致在该类型隐式转换为Object时执行装箱操作。因此,GetType总是返回一个表示底层类型的类型对象,而不是可为null的类型。 值得指出的是,你的标题中的区别是不准确的。类型行为并不是基于局部变量或属性的,而是基于是通过运行时对象还是通过反射(或使用typeof运算符)访问类型。您的推断是可以理解的,因为局部变量的类型通常只能通过运行时对象进行访问,但是,这是有缺陷的,因为如果您在运行时通过属性访问器访问可为null的对象,则其行为将与局部变量的行为等效


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

方法GetNullableUnderlyingType为可为null的类型返回基础类型,为其他类型返回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;
    }
}
类程序
{
静态void Main(字符串[]参数)
{
WriteLine(GetNulllableUnderlyingType(newTestClass().value));
WriteLine(GetNulllableUnderlyingType(newTestClass());
Console.ReadKey();
}
公共类TestClass
{
公共价值;
}
公共静态类型GetNulllableUnderlyingType(T值)
{
Type result=Nullable.getUnderlineType(typeof(T));
返回结果;
}
}

首先,示例中的
null.getunderyingtype(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
之前,您首先使用不同的类型,最终得到的结果不同。

smartcaveman的答案是迄今为止最好的答案,因为它实际上确定了文档中描述他对这种行为表示不满

这种行为是不受欢迎和不幸的;这是由于这种行为结合了三个特征,而这三个特征本身就表现得很合理

这三个特点是:

  • GetType
    是一个非虚拟的方法;它不能被重写。这应该是有意义的;对象不能决定它的报告类型。通过使其非虚拟,该方法可以保证说出真相

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

  • 可为null的值类型没有装箱形式;当您装箱可为null的int时,您要么得到装箱的int,要么得到null引用。您永远不会得到对装箱可为null的int的有效引用

每个特性本身都是合理的,但结合起来,结果是不可取的:当您对有效的可空int调用
GetType
时,运行时将可空int装箱为一个已装箱的int,然后将其作为
对象的
this
传递。GetType
当然会报告
int
。如果该值是可空的int时,运行时框设置为null,然后对null引用调用
GetType
,然后崩溃。这两种行为都不可取,但我们都被它们卡住了。

typeof(field.FieldType)==typeof(test.value)
?我可以想象,因为该方法是ca