【问题标题】:Is something wrong with the dynamic keyword in C# 4.0?C# 4.0 中的动态关键字有问题吗?
【发布时间】:2011-01-19 09:17:04
【问题描述】:

C# 4.0 动态使用有一些奇怪的行为:

using System;

class Program {
  public void Baz() { Console.WriteLine("Baz1"); }
  static void CallBaz(dynamic x) { x.Baz(); }

  static void Main(string[] args) {
    dynamic a = new Program();
    dynamic b = new { Baz = new Action(() => Console.WriteLine("Baz2")) };

    CallBaz(a); // ok
    CallBaz(b); // ok
    CallBaz(a); // Unhandled Exception:
    // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
    // The name 'Baz' is bound to a method and cannot be used like a property
  }
}

我正在使用 Visual Studio 2010 Release Candidate。

这是一个错误吗?如果是真的,会在 Release 中修复吗?

【问题讨论】:

  • 埃里克·利珀特在哪里:D
  • 我也可以重现它...对 CallBaz(a) 的第一次调用工作正常,第二次调用失败。它看起来确实像一个错误,而且是一个严重的错误......
  • 有趣。我已将一封电子邮件放入适当的列表中 - 希望它很快会得到一些关注。
  • ControlFlow,你应该认真考虑加入 .NET/C# 测试团队。这是您报告的第三个问题,Eric 已确认这是一个错误。
  • @Yogi True...谁是 ControlFlow?它是 C# 规范的拟人化吗?

标签: c# caching dynamic


【解决方案1】:

我可以确认这确实是一个错误。此处出现问题的简要说明如下: 在 CallBaz 中,有一个调用站点被调用了 3 次。该调用站点是一个 InvokeMember,因为这是编译器根据 C# 语法可以做出的最佳猜测,尽管它实际上可以解析为 GetMember,然后是 Invoke。

在调用站点的第二次执行期间,这确实是运行时找到的绑定。因此,它产生对 GetMember 的延迟,然后是调用。错误是这种延迟没有正确地将自身限制在参数是匿名类型的情况下。因此,在第三次执行中,延迟启动,GetMember 尝试绑定到 Program,这当然失败了。

感谢您找到这个。正如 Eric 指出的那样,我们处于非常晚的阶段,在我们发货之前解决问题变得越来越困难。但我们也想运送正确的产品。我会尽我所能来解决这个问题,尽管我可能不会成功。如果您有其他想法,请随时与我联系。 =)

更新:

虽然我不能保证 VS 2010 和 C# 4 的最终版本在发布时会是什么样子,但我可以说我成功地推动了这个修复。今天发布的托管构建对您的代码来说是正确的。除非发生一些灾难,否则您将在发布时看到此问题已修复。再次感谢。我欠你一杯啤酒。

【讨论】:

    【解决方案2】:

    看起来很可疑。我会把它送去测试,我们会看看他们怎么说。

    只是为了设定期望:如果这是一个错误,并且尚未被发现和修复,那么修复很有可能不会进入最终版本。

    感谢您提请我们注意!

    【讨论】:

      【解决方案3】:

      这看起来像一个严重的错误...

      请注意,如果您使用 ExpandoObject 而不是匿名类型,它可以正常工作:

      using System;
      using System.Dynamic;
      
      class Program {
        public void Baz() { Console.WriteLine("Baz1"); }
        static void CallBaz(dynamic x) { x.Baz(); }
      
        static void Main(string[] args) {
          dynamic a = new Program();
          dynamic b = new ExpandoObject();
          b.Baz = new Action(() => Console.WriteLine("Baz2"));
      
          CallBaz(a); // ok
          CallBaz(b); // ok
          CallBaz(a); // ok
        }
      }
      

      所以这个问题似乎是匿名对象特有的......

      显然,在对CallBaz(a) 的第二次调用中,DLR 仍然尝试将Baz 作为属性进行访问,因为它是匿名类型的属性。我怀疑 C# 绑定器对调用解析进行了一些缓存以获得更好的性能,但在这种情况下,它显然被破坏了......

      【讨论】:

        【解决方案4】:

        同样的事情发生在我身上,我建议你报告它here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-08
          • 2010-10-01
          • 1970-01-01
          • 2011-06-01
          • 2010-09-22
          • 2011-02-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多