使用’var’和’dynamic’时的exception

我在Anomaly上碰到了一点,这是第一次使用var关键字我。

采用这种非常简单的方法

 public static Int32? GetNullableInt32(Int32 num) { return new Nullable(num); } 

现在我们可以使用dynamic参数调用此方法,一切都将按预期工作。

 public static void WorksAsAdvertised() { dynamic thisIsAnInt32 = 42; //Explicitly defined type (no problems) Int32? shouldBeNullableInt32 = GetNullableInt32(thisIsAnInt32); Console.Write(shouldBeNullableInt32.HasValue); } 

但是,通过使用隐式类型声明shouldBeNullableInt32 ,结果远非所期望的。

 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 ,返回值被视为动态类型。 即使这样,底层的Nullable也不会被保留。 由于System.Int32没有名为HasValue属性,因此抛出RuntimeBinderException

我会非常好奇地听到能够解释正在发生的事情的人(不仅仅是猜测)。

两个问题

  1. GetNullableInt32的返回类型明确返回Nullable时,为什么shouldBeNullableInt32隐式输入为动态
  2. 为什么不保留底层Nullable ? 为什么dynamic{int}呢? 这里回答 : C#4:Dynamic和Nullable )

UPDATE

Rick Sladkey的回答和Eric Lippert的回答都同样有效。 请阅读他们:)

  1. GetNullableInt32的返回类型明确返回Nullable时,为什么shouldBeNullableInt32隐式输入为动态

这是因为虽然我们很明显GetNullableInt32是将要调用的方法, 由于动态绑定 ,实际调用的方法将延迟到运行时,因为它是使用动态参数调用的。 可能还有另一个GetNullableInt32重载,它更好地匹配thisIsAnInt32的运行thisIsAnInt32 。 那个替代方法,直到运行时才能知道, 可能会返回除Int32?之外的其他类型Int32?

因此,由于动态绑定而不是静态绑定,编译器无法在编译时假设表达式的返回类型,因此表达式返回类型dynamic 。 这可以通过将鼠标hover在var看到。

你似乎已经对你的第二个问题得到了令人满意的解释:

  • C#4:动态和可空<>

Rick的答案很好,但总而言之,您正在遇到该function的两个基本设计原则的后果:

  1. 如果你要求动态绑定,那么你会得到动态绑定
  2. 动态只是戴着滑稽帽子的对象

您确定的第一个问题是第一个设计原则的结果。 您要求分析要延迟到运行时的调用。 编译器这样做了。 这包括将有关调用的所有内容推迟到运行时,包括重载解析和确定返回类型。 编译器有足够的信息来猜测你的意思是无关紧要的。

如果编译器确实猜到了你的意思,那么现在你会问一个不同的问题,即“我对可用的方法集进行了微小的改动,然后编译器突然改变了对类型的推导动态,为什么?“ 当编译器的行为不可预测时,用户会非常困惑。

(尽管如此,编译器会告诉您动态代码错误的情况很少。在某些情况下我们知道动态绑定在运行时总会失败,我们可以在编译时告诉您它们时间而不是等待你的测试用例失败。)

您确定的第二个问题是第二个设计原则的结果。 因为动态只是戴着滑稽帽子的对象,并且因为nullables框为空引用或盒装不可空值类型,所以没有“动态可空”这样的东西。