con*_*low 50 c# caching dynamic
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
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用Visual Studio 2010 Release Candidate.
这是一个错误吗?如果是真的,它会在Release中修复吗?
Chr*_*ows 32
我可以确认这确实是一个错误.这里出现问题的快速描述如下:在CallBaz中,有一个调用三次的调用点.该callsite是一个InvokeMember,因为这是编译器在给定C#语法时可以做出的最佳猜测,尽管它实际上可以解析为GetMember,然后是Invoke.
在第二次执行调用站点期间,这确实是运行时找到的绑定.因此它会产生一个GetMember的延迟,然后是一个调用.问题是这种推迟不能正确地将自己限制在参数是匿名类型的情况下.因此,在第三次执行中,推迟启动并且GetMember尝试绑定到Program,这当然会失败.
谢谢你找到了这个.正如埃里克指出的那样,我们现在处于非常晚期阶段,在我们出货之前解决问题变得越来越困难.但我们也想发运正确的产品.尽管我可能没有成功,但我会尽我所能来解决这个问题.如果您想出其他任何事情,请随时与我联系.=)
更新:
虽然我无法保证VS 2010和C#4的最终版本在发布时会是什么样子,但我可以说我成功地推动了这个修复.今天的发布托管版本对您的代码运行正常.除非发生一些灾难,否则你会在发布时看到这个问题.再次感谢.我欠你一杯啤酒.
Eri*_*ert 11
看起来很可疑.我会发送它进行测试,我们会看到他们说的话.
只是为了设定期望:如果这是一个错误,并且它还没有找到并修复,那么赔率很高,修复不会进入最终版本.
谢谢让我们注意到这个!
这看起来像一个严重的错误......
请注意,如果您使用的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
}
}
Run Code Online (Sandbox Code Playgroud)
所以问题似乎特定于匿名对象......
显然,在第二次调用中CallBaz(a),DLR仍然尝试Baz作为属性进行访问,因为它是匿名类型的属性.我怀疑C#binder对呼叫解决方案进行了一些缓存,以获得更好的性能,但在这种情况下,它显然已被打破......
| 归档时间: |
|
| 查看次数: |
1698 次 |
| 最近记录: |