使用'var'和'dynamic'时的异常

时间:2011-09-16 02:49:21

标签: c# dynamic compiler-construction

我在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

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

两个问题

  1. shouldBeNullableInt32的返回类型明确返回GetNullableInt32时,为什么Nullable<Int32>隐式输入为动态
  2. 为什么未保留基础Nullable<Int32>?为什么选择dynamic{int}在此回答C# 4: Dynamic and Nullable<>

  3. 更新

    Rick Sladkey's answerEric Lippert's answer同样有效。请阅读它们:)

2 个答案:

答案 0 :(得分:19)

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

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

因此,由于动态绑定而不是静态绑定,编译器不能假设表达式的返回类型在编译时是什么,因此表达式返回类型 dynamic < / strong>即可。将其悬停在var上即可看出。

您似乎已经在第二个问题上找到了令人满意的解释:

答案 1 :(得分:17)

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

  1. 如果您要求动态绑定,那么您将获得动态绑定
  2. 动态只是戴着滑稽帽子的对象
  3. 您确定的第一个问题是第一个设计原则的结果。您要求分析要延迟到运行时的调用。编译器这样做了。这包括将关于调用的所有推迟到运行时,包括重载解析和确定返回类型。编译器有足够的信息来猜测你的意思是无关紧要的。

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

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

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