为什么IsAssignableFrom在将nullable与接口进行比较时返回false?

tig*_*rou 11 c# types

C#中的以下调用返回false:

typeof(IComparable).IsAssignableFrom(typeof(DateTime?))
Run Code Online (Sandbox Code Playgroud)

但是,以下行完全有效:

IComparable comparable = (DateTime?)DateTime.Now;
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

是因为使用了可空类型Nullable<T>,第一个泛型参数实现接口的事实并不意味着Nullable类也实现了该接口?(例如:List<Foo>不实现实现的接口Foo)

编辑:我认为上面的行编译,因为当装箱一个可空类型时,只有底层类型被装箱,如下所述:https://msdn.microsoft.com/en-us/library/ms228597.aspx

Mat*_*son 11

此行为的原因是IsAssignableFrom()不考虑编译器为可空类型的转换发出的特殊装箱转换.

请注意,您实际上并不需要在问题中使用强制转换.

代替

 IComparable comparable = (DateTime?)DateTime.Now;
Run Code Online (Sandbox Code Playgroud)

你可以写:

DateTime? test = DateTime.Now;
IComparable comparable = test;
Run Code Online (Sandbox Code Playgroud)

这些行中的第一行编译因为Nullable<T>提供了隐式转换运算符:

public static implicit operator Nullable<T> (
    T value
)
Run Code Online (Sandbox Code Playgroud)

第二行导致编译器发出一个box指令:

L_000e: box [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>
Run Code Online (Sandbox Code Playgroud)

这个装箱操作由C#语言规范的第6.1.7节,Boxing转换(这包括具体为可空类型的装箱转换)所述,其中规定:

装箱转换允许将值类型隐式转换为引用类型.从任何非可空值类型到对象和动态,到System.ValueType 以及由非可空值类型实现的任何接口类型都存在装箱转换.此外,枚举类型可以转换为System.Enum类型.

当且仅当从基础非可空值类型到引用类型存在装箱转换时,存在从可空类型到引用类型的装箱转换.

如果值类型具有到接口类型I0的装箱转换并且I0具有到I的标识转换,则值类型具有到接口类型I的装箱转换.

如果一个值类型具有到接口或委托类型I0的装箱转换,并且I0是方差可转换(第13.1.3.2节)到I,则它具有到接口类型I的装箱转换.

装箱非可空值类型的值包括分配对象实例并将值类型值复制到该实例中.结构可以装入System.ValueType类型,因为它是所有结构的基类(第11.3.2节).

这就是上面的拳击操作.我用粗体和斜体来表达最相关的观点.

另请参阅此链接(由OP提供):https://msdn.microsoft.com/en-us/library/ms228597.aspx