【发布时间】:2012-04-28 07:13:08
【问题描述】:
我在Nullable 和隐式转换之间的交互中遇到了一些有趣的行为。我发现为引用类型从值类型提供隐式转换,它允许将 Nullable 类型传递给需要引用类型的函数,而我却期望出现编译错误。下面的代码演示了这一点:
static void Main(string[] args)
{
PrintCatAge(new Cat(13));
PrintCatAge(12);
int? cat = null;
PrintCatAge(cat);
}
private static void PrintCatAge(Cat cat)
{
if (cat == null)
System.Console.WriteLine("What cat?");
else
System.Console.WriteLine("The cat's age is {0} years", cat.Age);
}
class Cat
{
public int Age { get; set; }
public Cat(int age)
{
Age = age;
}
public static implicit operator Cat(int i)
{
System.Console.WriteLine("Implicit conversion from " + i);
return new Cat(i);
}
}
输出:
The cat's age is 13 years
Implicit conversion from 12
The cat's age is 12 years
What cat?
如果从Cat 中删除转换代码,那么您会得到预期的错误:
Error 3 The best overloaded method match for 'ConsoleApplication2.Program.PrintCatAge(ConsoleApplication2.Program.Cat)' has some invalid arguments
Error 4 Argument 1: cannot convert from 'int?' to 'ConsoleApplication2.Program.Cat
如果您使用 ILSpy 打开可执行文件,则生成的代码如下
int? num = null;
Program.PrintCatAge(num.HasValue ? num.GetValueOrDefault() : null);
在一个类似的实验中,我删除了转换并向PrintCatAge 添加了一个重载,它接受一个 int(不可为空)来查看编译器是否会执行类似的操作,但它不会。
我明白发生了什么,但我不明白这样做的理由。这种行为对我来说是出乎意料的,而且看起来很奇怪。我在 MSDN 上的转换文档或 Nullable<T> 中没有成功找到对此行为的任何引用。
然后我提出的问题是,这是故意的吗?是否有解释为什么会发生这种情况?
【问题讨论】:
-
有趣!一个类似的意外行为是 ((object)(int?)null) == null 为真。可以为空的 int 可以装箱到空引用。
-
像这样铸造一个空值:
(int?)null被优化掉了。但是, (null as int?) 会导致实际创建 int?临时变量。无论哪种方式,我都希望在这些情况下null == null。 -
@usr:这是意料之中的; CLR 具有用于装箱空值的特殊代码。实际上根本不可能得到一个盒装的
Nullable<T>。 -
等效的 VB.NET 代码在编译时确实会在
PrintCatAge(cat)上报错:“Option Strict On 不允许来自 'Integer?' 的隐式转换?到'UserQuery.Cat'。”并且在运行时使用Option Strict Off,它会失败并显示“InvalidOperationException:Nullable object must have a value。”。
标签: c# .net nullable implicit-conversion