比尔有什么区别?
比尔所做的区别在于,许多人认为:
var x = Whatever();
x.Foo();
将在运行时根据Whatever在运行时返回的对象类型计算出调用什么方法Foo。这不是真的; 那将是
dynamic x = Whatever();
x.Foo();
只是意味着“在编译时计算var
出类型并将其替换”,而不是“在运行时计算出来”。
所以如果我有
dynamic i = 5;
Console.WriteLine(i);
发生什么了?
编译器生成的代码在道德上是这样的:
object i = (object)5;
DynamicCallSite callSite = new DynamicCallSite(typeof(Console), "WriteLine"));
callSite.Invoke(i);
它比这更复杂一些;一方面,调用站点被缓存。但这给了你它的味道。
调用方法i
通过询问其类型GetType
,然后启动可以理解反射对象的特殊版本的 C# 编译器。它对Console
named的成员进行重载决议WriteLine
,并确定Console.WriteLine
将被调用的哪个重载首先i
被键入为 int。
然后它生成表示该调用的表达式树,将表达式树编译为委托,将其缓存在调用站点中,并调用委托。
第二次执行此操作时,缓存的调用站点在其缓存中查找,并看到最后一次i
是 int,调用了特定的委托。因此,它第二次跳过创建调用站点并进行重载解析,而只是调用委托。
有关更多信息,请参阅:
http://ericlippert.com/2012/10/22/a-method-group-of-one/
http://ericlippert.com/2012/11/05/dynamic-contagion-part-one/
http://ericlippert.com/2012/11/09/dynamic-contagion-part-two/
可以从 Chris 和 Sam 的博客中获得有关该功能的历史观点:
http://blogs.msdn.com/b/cburrows/archive/tags/dynamic/
http://blogs.msdn.com/b/samng/archive/tags/dynamic/
他们做了很多实施;然而,其中一些文章反映了过时的设计选择。遗憾的是,我们从未使用过“幻影法”算法。(不是一个伟大的算法,但一个伟大的名字!)