2011-05-17 76 views
17

令人惊讶的是下面的代码失败的断言:通过反射检测可空类型

int? wtf = 0; 
Assert.IsType<Nullable<int>>(wtf); 

所以只是出于好奇,你怎么能确定给定的情况下是可空<>对象或没有?

+1

的可能重复[如何检查对象是否为空?](http://stackoverflow.com/questions/374651/how-检查对象是否可为空) – nawfal 2013-10-10 07:07:12

回答

38

那么首先,Nullable<T>是一个结构体,所以没有这样的对象对象。你不能调用GetType(),因为这会填充值(在这一点上你得到空值,因此是一个例外,或一个盒装非空值,因此不是你想要的类型)。

(拳击是怎么在这里搞乱你的断言 - 我会假设,IsType接受object。)

您可以使用类型推断,虽然得到变量的类型作为类型参数:

public bool IsNullable<T>(T value) 
{ 
    return Nullable.GetUnderlyingType(typeof(T)) != null; 
} 

当你在编译时知道确切的类型时,这不是一个巨大的使用量,就像在你的例子中那样,但它对泛型很有用。 (当然,还有其他的实现方法)。

你的真实生活情况如何?我认为这不是一个这样的断言,因为你在编译时知道这个答案。

+1

非常棘手!似乎这样做。现在我只需要记住为什么我想知道那个...... – 2011-05-17 06:14:02

+0

另外我从来没有意识到结构体没有GetType(),但是我应该明白这一点,因为我明白它们被装箱得到这样的东西。 – 2011-05-17 06:15:00

+0

@ justin.m.chase: - 而是因为调用非虚,他们不能重写* *它,这意味着该值始终装箱......然后螺丝事情的Structs从'object'继承'GetType'当原始值可以为空时启动。 – 2011-05-17 06:17:14

0

什么命名空间是Assert in?

下返回true如你所愿:

int? wtf = 0; 
if (typeof(Nullable<int>).IsInstanceOfType(wtf)) 
{ 
    // Do things 
} 

虽然它值得注意的是,typeof(Nullable<int>).IsInstanceOfType(42)也返回true - 这是因为该方法接受一个object等被盒装的Nullable<int>

+0

断言是xUnit的,但我只是想在一般的说,该声明应该会成功。 – 2011-05-17 06:08:32

+0

另外,我不认为上述作品......嗯技术上它返回true,但我相信这是一个假阳性,因为这也将返回true:typeof运算(可空).IsInstanceOfType(0) – 2011-05-17 06:09:15

+0

@Kragen:用试试吧' int wtf = 0;'和'int? wtf = null;'一些令人惊讶的结果。拳击使得这种方法签名无法真正做到你想要的。编辑:在你编辑之后,仍然有一个问题 - '42'' *不会*作为'Nullable '装箱。相反,'0'被装箱为'int'装箱类型。没有办法构造可空类型的盒装值。 – 2011-05-17 06:09:22

1
int? i = 0; 
var type = TypedReference.GetTargetType(__makeref(i)); 
var isNullable = type.IsGenericType && 
    type.GetGenericTypeDefinition() == typeof(Nullable<>); 
+0

这是辉煌的,它给出了声明的类型(不像'object i = 0; i.GetType()== typeof(int);'')中的底层类型。但是如果要获得声明类型,为什么不简单地使我们的类型推断?就像'public Type GetDeclaredType (this T t){return typeof(T); }'。更可读。 – nawfal 2016-07-02 07:10:15

0

这里是我想出了,周围的一切似乎失败 - 至少在便携式类库/DOTNET的核心与> = C#6

基本上你扩展泛型类型ObjectNullable<T>,并使用匹配基础类型的静态扩展方法将被调用并优先于通用T扩展方法的事实。

public static partial class ObjectExtension 
{ 
    public static bool IsNullable<T>(this T self) 
    { 
     return false; 
    } 
} 

,一个用于Nullable<T>

public static partial class NullableExtension 
{ 
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct 
    { 
     return true; 
    } 
} 

使用反射和type.IsGenerictype.GetGenericParameters()没有对我目前的.NET运行时的工作。

2

我喜欢@ jon-spectet答案,但它只适用于你知道你正在测试的类型。在我们的世界中,我们使用反射来打开对​​象,并根据正则表达式测试值。

简化任何类型的扩展工作对我们来说都更好。

public static bool IsNullable(this Type type) 
{ 
    return Nullable.GetUnderlyingType(type) != null; 
} 

泛型是生命的血液,但有时... :)