当dynamic遭遇匿名对象所造成的问题初步研究结论。
2010-05-21 03:22 Ivony... 阅读(3079) 评论(7) 编辑 收藏 举报问题是在老赵的博客上看到的:
看到问题后,我的直觉的第一反应觉得这个问题一定是某种特定条件下必然会触发的Bug,与ASP.NET MVC没啥关系。但当时比较懒,做了几次试验后就暂且搁下了。后来swanky.wu同学推进了一把问题的研究,指出:
“当用dynamic在某个程序集中定义动态类型后,然后使用匿名类型对象对其赋值,再然后在另一个程序集访问这个动态类型的匿名对象的属性就会发生这个异常;在同一个程序集中访问中没有发现问题。”
今天终于有时间好好来研究这个问题,首先我按照swanky.wu同学的线索做了一个简单的实验来重现了这个问题。然后不断的撤除附加条件,得到了最简能重现问题的代码(事实上与匿名类型没啥关系):
namespace BugTest2 { public static class Test { private class Value { public string Title = "Hello World"; } public static dynamic GetValue() { return new Value(); } } public class Program { static void Main( string[] args ) { var d = Test.GetValue(); Console.WriteLine( d.Title ); Console.ReadLine(); } } }
问题到这里就非常清楚了,当通过dynamic访问可见性在当前上下文不可见的成员的时候,就会引发这个异常。
那么为什么匿名类型一定会出问题呢?这是因为C#的编译器总是会将匿名类型编译成internal的。这就使得匿名类型在跨程序集透过dynamic访问的时候,就一定会出这个问题了。
如何解决?
事实上问题的根本在于C#的编译器总是会将匿名类型编译成internal的类型。而我暂时也没有找到什么办法可以让C#编译出public的匿名类型。所以这个问题目前来说,还只能用老赵的那个辅助方法,不过我建议更名为ToPublic更为恰当,因为那个方法解决问题的本质在于Public这个类型。
为什么说是初步研究结论?
因为尽管我已经把C#针对dynamic对象所产生的那些代码研究了半天,但我还是没有找到异常触发的根本位置,所以现在的结论还是建立在试验和观察上,并没有实现代码作为佐证。。。。
怨念啊。。。
嗯嗯,System.CSharp.RuntimeBuilder.CSharpGetMemberBinder这个类型应该是关键。。。。。