2013-02-13 107 views
3

The C# Programming language比尔·瓦格纳说:动态绑定VS类型推断

很多人混淆了类型推断动态bindig。类型 推断是静态绑定的。编译器在编译时确定类型 。例如:

var i = 5;    //i is an int (Compiler performs type inference) 
Console.WriteLine(i); //Static binding to Console.WriteLine(int) 

编译器推断出我是一个整数。所有绑定变量 我使用静态绑定。

现在,鉴于此信息,我自己编造的动态之情况:

 dynamic i = 5;  //Compiler punts 
     Console.WriteLine(i);//This is now dynamically bound 

我们知道类型推断静态绑定。这意味着动态变量无法使用类型推断来确定类型。如何在不使用类型推断的情况下解决动态类型?

更新
要尝试,并在运行时,我们必须设法弄清楚我是什么类型的正确澄清......?因为我分配了文字5,运行时可以推断iint。不是那种类型推断而不是动态绑定?

+0

动态的基础类型(这是一种语言结构,在元数据中除了属性外没有表示)是'System.Object'。这是C#编译器魔术,它允许您动态调用方法并访问其上的字段(在本例中为盒装整型),而无需自己进行反射。 – 2013-02-13 17:56:07

回答

6

比尔制作有什么区别?

,比尔正在的区别是,很多人都认为:

var x = Whatever(); 
x.Foo(); 

将制定出在运行时有什么方法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); 

它比更复杂一点;呼叫站点被缓存了一件事。但是这给你它的味道。

调用方法通过GetType询问i的类型,然后启动可以理解反射对象的特殊版本的C#编译器。它确实对名为WriteLineConsole的成员重载分辨率,并且确定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/

要素上历史的角度可以从克里斯和萨姆的博客获得:

http://blogs.msdn.com/b/cburrows/archive/tags/dynamic/

http://blogs.msdn.com/b/samng/archive/tags/dynamic/

他们做了很多实现;然而这些文章中的一些反映了过时的设计选择。令人遗憾的是,我们从未使用过“幽灵方法”算法。 (不是一个很好的算法,而是一个伟大的名字!)

+0

我明白了,所以'动态'并不经过7.5.2节定义的类型推断过程。相反,'i.GetType()'用于在运行时确定类型。 – 2013-02-13 18:10:53

+0

或者更确切地说......在你更新之后,他会比较'var'和'dynamic'。这就说得通了! – 2013-02-13 18:16:11

+1

@ P.Brian.Mackey:第7.5.2节是*通用方法类型推断*。 Bill正在讨论的部分是关于*隐式键入的局部变量声明*的第8.5.1节。 – 2013-02-13 18:56:41