我在Anomaly上遇到过一些问题,这是第一次使用var
关键字对我说。
采用这个非常简单的方法
public static Int32? GetNullableInt32(Int32 num)
{
return new Nullable<Int32>(num);
}
现在我们可以使用dynamic
参数调用此方法,一切都将按预期工作。
public static void WorksAsAdvertised()
{
dynamic thisIsAnInt32 = 42;
//Explicitly defined type (no problems)
Int32? shouldBeNullableInt32 = GetNullableInt32(thisIsAnInt32);
Console.Write(shouldBeNullableInt32.HasValue);
}
但是,通过使用隐式类型声明shouldBeNullableInt32
,结果远非 I 所期望的。
public static void BlowsUpAtRuntime()
{
dynamic thisIsAnInt32 = 42;
//Now I'm a dynamic{int}... WTF!!!
var shouldBeNullableInt32 = GetNullableInt32(thisIsAnInt32);
//Throws a RuntimeBinderException
Console.Write(shouldBeNullableInt32.HasValue);
}
而不是Nullable<Int32>
返回值get被视为动态类型。即便如此,基础Nullable<T>
也不会被保留。由于System.Int32
没有名为HasValue
的属性,因此会抛出RuntimeBinderException
。
我会非常非常好奇地听到能够解释正在发生的事情的人(不仅仅是猜测)。
shouldBeNullableInt32
的返回类型明确返回GetNullableInt32
时,为什么Nullable<Int32>
将隐式输入为动态?Nullable<Int32>
?为什么选择dynamic{int}
? (在此回答:C# 4: Dynamic and Nullable<>) Rick Sladkey's answer和Eric Lippert's answer同样有效。请阅读它们:)
答案 0 :(得分:19)
- 当
醇>shouldBeNullableInt32
的返回类型明确返回GetNullableInt32
时,为什么Nullable<Int32>
将隐式输入为动态?
这是因为虽然我们很明显GetNullableInt32
是要调用的方法,因为dynamic binding,做的实际方法被调用延迟到运行时,因为它是使用动态参数调用的。 GetNullableInt32
的另一个重载可能会更好地匹配thisIsAnInt32
的运行时值。这种替代方法,直到运行时才能知道,可能会返回除Int32?
以外的其他类型!
因此,由于动态绑定而不是静态绑定,编译器不能假设表达式的返回类型在编译时是什么,因此表达式返回类型 dynamic < / strong>即可。将其悬停在var
上即可看出。
您似乎已经在第二个问题上找到了令人满意的解释:
答案 1 :(得分:17)
Rick的回答很好,但总而言之,您正在遇到该功能的两个基本设计原则的后果:
您确定的第一个问题是第一个设计原则的结果。您要求分析要延迟到运行时的调用。编译器这样做了。这包括将关于调用的所有推迟到运行时,包括重载解析和确定返回类型。编译器有足够的信息来猜测你的意思是无关紧要的。
如果编译器确实猜到了你的意思,那么现在你会问一个不同的问题,即“我对可用的方法集进行了微小的改动,突然编译器改变了它的推论动态的类型,为什么?“当编译器的行为不可预测时,用户会非常困惑。
(总而言之,有少数情况下编译器会告诉您动态代码是错误的。在某些情况下我们知道动态绑定总是在运行时失败,我们可以在编译时告诉你它们,而不是等待你的测试用例失败。)
您确定的第二个问题是第二个设计原则的结果。因为动态只是戴着滑稽帽子的对象,并且因为nullables框为空引用或盒装不可空值类型,所以没有“动态可空”这样的东西。