如何确定一个非空对象是否是可空结构体?

5
有没有办法知道这个问题的答案?
我在一个帖子中找到了一个非常类似的问题,位于如何检查对象是否可为空 。答案解释了如何确定对象是否可为空,如果有访问通用类型参数,则可以使用Nullabe.GetUnderlyingType(typeof(T))。但是,如果您只有一个不为null的对象,您能否确定它实际上是可空值类型?
换句话说,除了逐个检查每个可能的可空值类型之外,是否有更好的方法来确定装箱结构是否为值类型?
void Main(){
    Console.WriteLine(Code.IsNullableStruct(Code.BoxedNullable));
} 


public static class Code{
    private static readonly int? _nullableInteger = 43;

    public static bool IsNullableStruct(object obj){
                  if(obj == null) throw new ArgumentNullException("obj");
                  if(!obj.GetType().IsValueType) return false;
                  return IsNullablePrimitive(obj);
            }
    public static bool IsNullablePrimitive(object obj){
         return obj is byte? || obj is sbyte? || obj is short? || obj is ushort? || obj is int? || obj is uint? || obj is long? || obj is ulong? || obj is float? || obj is double? || obj is char? || obj is decimal? || obj is bool? || obj is DateTime? || obj is TimeSpan?;
    }

    public static object BoxedNullable{
        get{ return _nullableInteger; }
    }
}

更新

我在MSDN的这篇文章中发现,无法通过调用GetType()方法来确定一个类型是否为可空结构。

更新 #2

显然,我建议的方法也不起作用,因为int x = 4; Console.WriteLine(x is int?);的结果是True。(请参阅评论)


那实际上是不起作用的。如果 obj 是 int,则 obj is int? == true - porges
4个回答

4
引用Jon Skeet在你链接的问题中的评论:
“不存在装箱的可空类型——Nullable会被装箱为一个null引用或一个装箱的int。”
因此,在你的示例程序中,当BoxedNullable被传递给以object作为参数的IsNullableStruct时,该值已经是一个装箱的43,不再是可空类型。具有讽刺意味的是,x is int?对于任何int(包括可空和非可空类型)都是true,这只会增加混乱。
无论如何,根据Jon的评论,你最初的问题似乎没有意义。

1
这是一篇关于 MSDN 的文章,解释了这个问题。 - porges

1

当你将一个可空类型装箱时,它实际上是将其基础类型装箱。Nullable<int> 将变成一个装箱的 int。没有办法判断装箱值类型的来源是否为 Nullable。

请注意,如果你传递一个非 Nullable 的 int 给你的 IsNullablePrimitive,它实际上会返回 true!


0

Nullable<> 是一个特殊的类。当您尝试检查或复制 Nullable<> 时,它会被转换/装箱为 'null' 或它所包含的值类型。如果您的 Nullable<> 没有值,则调用 GetType() 实际上会抛出异常,或者最多返回基础类型。欺骗发生在最低级别。您无法通过任何合法手段识别 Nullable<>。


-1

是的,你只需要检查通用定义:

protected bool IsNullableType(Type type)
{
    if(!type.IsGeneric)
        return false;

    return type.GetGenericDefinition() == typeof(Nullable<>);
}

实际上,这些语句是相同的:

var type = typeof(Nullable<>);
var type2 = new Nullable<int>().GetType().GetGenericDefinition();

(1) 你的语法有误。 (2) 假设你想要等价于 return !type.IsGenericType ? false : type.GetGenericTypeDefinition() == typeof(Nullable<>);,你的答案仍然是不正确的。这两个语句并不等价,请试一下。 - smartcaveman
2
这些语句并不相同。Nullable<T>.GetType()实际上返回的是T。 - Cory Nelson
有趣。我每天都学到新东西!我本以为它会像其他大多数泛型一样工作。 - Tejs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接