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

Jos*_*osh 28 c# compiler-construction dynamic

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

采用这种非常简单的方法

public static Int32? GetNullableInt32(Int32 num)
{
    return new Nullable<Int32>(num);
}
Run Code Online (Sandbox Code Playgroud)

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

public static void WorksAsAdvertised()
{
    dynamic thisIsAnInt32 = 42;

    //Explicitly defined type (no problems)
    Int32? shouldBeNullableInt32 = GetNullableInt32(thisIsAnInt32);

    Console.Write(shouldBeNullableInt32.HasValue);
}
Run Code Online (Sandbox Code Playgroud)

但是,通过声明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);
}
Run Code Online (Sandbox Code Playgroud)

而不是Nullable<Int32>返回值get被视为动态类型.即便如此,底层Nullable<T>也不会被保留.由于System.Int32没有命名的属性HasValue,RuntimeBinderException因此抛出了a .

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

两个问题

  1. 为什么shouldBeNullableInt32得到隐式类型为动态时的返回类型GetNullableInt32显然返回Nullable<Int32>
  2. 为什么底层Nullable<Int32>没有保留?为什么dynamic{int}反而?(这里回答:C#4:Dynamic和Nullable <>)

UPDATE

无论里克Sladkey的回答埃里克利珀的回答同样有效.请阅读他们:)

Ric*_*key 20

  1. 为什么shouldBeNullableInt32得到隐式类型为动态时的返回类型GetNullableInt32显然返回Nullable<Int32>

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

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

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


Eri*_*ert 18

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

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

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

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

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

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