Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.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#_.net_Nullable_Gettype - Fatal编程技术网

C# 可空类型不是可空类型吗?

C# 可空类型不是可空类型吗?,c#,.net,nullable,gettype,C#,.net,Nullable,Gettype,我用可空类型进行了一些测试,但它并没有像我预期的那样工作: int? testInt = 0; Type nullableType = typeof(int?); Assert.AreEqual(nullableType, testInt.GetType()); // not the same type 这也不起作用: DateTime? test = new DateTime(434523452345); Assert.IsTrue(test.GetType() == typeof(Null

我用可空类型进行了一些测试,但它并没有像我预期的那样工作:

int? testInt = 0;
Type nullableType = typeof(int?);
Assert.AreEqual(nullableType, testInt.GetType()); // not the same type
这也不起作用:

DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable)); //FAIL 

DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable<>)); //STILL FAIL
DateTime?测试=新日期时间(43452345235);
Assert.IsTrue(test.GetType()==typeof(null))//失败
约会时间?测试=新日期时间(43452345235);
Assert.IsTrue(test.GetType()==typeof(null))//仍然失败
我的问题是为什么testInt.GetType()返回int,而typeof(int?)返回真正的可为null的类型?

根据:

对可为空的类型调用GetType 使装箱操作失败 当类型为隐式时执行 转换为对象。因此GetType 始终返回一个 表示基础类型,而不是 可为空的类型

当您装箱一个可为空的对象时,只装箱基础类型

同样,来自:

装箱一个非空的可空值类型 框中的值类型本身,而不是 包装该值的System.Nullable 类型


根据Romain的正确答案,如果要比较“真实”类型(即,不隐式地将任何可空类型转换为其基础类型),则可以创建如下扩展方法:

public static class MyExtensionMethods
{
    public static Type GetRealType<T>(this T source)
    {
        return typeof(T);
    }
}
编辑…

为了完整性——并根据SLaks下面的评论——这里有一个替代版本,它只在
source
null
可为null
时使用编译时类型;否则,它使用
GetType
并返回运行时类型:

public static class MyExtensionMethods
{
    public static Type GetRealType<T>(this T source)
    {
        Type t = typeof(T);

        if ((source == null) || (Nullable.GetUnderlyingType(t) != null))
            return t;

        return source.GetType();
    }
}
公共静态类MyExtensionMethods
{
公共静态类型GetRealType(此T源)
{
类型t=类型(t);
if((source==null)| |(null.getUnderlineType(t)!=null))
返回t;
返回source.GetType();
}
}
尽管C#假装值类型存储位置保存从
System.ValueType
派生的类型的实例,而后者又从
System.Object
派生,但事实并非如此。从
System.ValueType
派生的每种类型实际上代表两种截然不同的事物:

  • 字节的集合,它(对于基本类型)直接表示数据,或者(对于非基本结构类型)包含所有字段(公共和私有)的内容,但不包含任何类型信息。
  • 一个独立的堆对象,除上述对象外还包含一个对象头,其类型派生自“System.ValueType”。 值类型的存储位置保存第一个值;值类型的堆对象持有第二个值

    出于各种原因,微软决定
    Nullable
    只支持第一次使用。如果试图将类型为
    Nullable
    的存储位置传递给希望引用堆对象的代码,则如果
    HasValue
    为true,系统将该项转换为
    T
    ,或者如果
    HasValue
    为false,则只传递null引用。虽然有一些方法可以创建类型为
    Nullable
    的堆对象,但是将值类型存储位置转换为堆对象的常规方法永远不会生成堆对象


    还要注意,对值存储位置调用
    GetType()
    实际上不会计算存储位置的类型,而是将该存储位置的内容转换为堆对象,然后返回结果对象的类型。由于类型为
    Nullable
    的存储位置被转换为
    T
    的对象实例或null,因此对象实例中的任何内容都不会说明其来源的存储位置是否为
    Nullable

    一种使用“is”操作符检查的简单方法:

    (i is Nullable<int>) || (i is Nullable<long>) || (i is Nullable<float>) || (i is Nullable<short>)
    
    (i可为空)| |(i可为空)| |(i可为空)| |(i可为空)
    
    我发现ti正在阅读这两个MSDN页面:


    干杯

    请注意,这将获得编译时类型。@SLaks:是否有过nullable的运行时类型与编译时类型不同的情况?(我很感激您可以将任何类型传递给这个方法,在这种情况下,您确实可以获得运行时类型,但它的目的是获得可为null的“真实”类型,正如问题所述。)您是对的<代码>((int?)2)。GetRealType()
    实际上不算数<代码>((对象)可空)。GetRealType()不明确。@SLaks:Oops,我的意思是“…在这种情况下,您确实会得到编译时类型”。是的,当您调用
    ((object)nullable).GetRealType()
    时,您将不再传递一个nullable。您正在传递nullable的基础类型的装箱值,或者只传递纯null。您可以提到,为了使用第二个版本,不能装箱nullable变量。另外,将您的第一个版本重命名为GetCompileType可以清楚地了解此方法的真正功能。它的伸缩性不是很好,是吗?可为空的、可为空的等
    (i is Nullable<int>) || (i is Nullable<long>) || (i is Nullable<float>) || (i is Nullable<short>)