今天读到了《CLR via C#》中动态基元类型的章节,刚好刚刚在候选区看到了一篇《为何能够说Java语言是准动态语言?》的文章,其文中说Java依赖反射能够称为‘准动态语言’,而C#是静态语言。程序员
我先不说结论,先来看一下什么是动态语言。编程
引用互动百科的词条:函数
动态语言,准确地说,是指程序在运行时能够改变其结构:新的函数能够被引进,已有的函数能够被删除等在结构上的变化。好比众所周知的ECMAScript(JavaScript)即是一个动态语言。除此以外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。性能
好比咱们在JavaScript里面能够这样写:spa
1 var temp = {}; 2 temp.FuncA = function(){ 3 console.log('FuncA Invoked') 4 } 5 temp.Name = 'JavaScript';
在以上代码中,对象temp是一个匿名对象,不具备类型结构。而后咱们为temp动态追加了一个函数 FuncA和一个属性Name 。之因此能够这样写,是由于JavaScript是一种解释型语言,全部的代码只有在运行时才会被解释器编译。而C语言,Java语言以及.Net 3.5及之前版本的C#语言,是运行前已经被编译为机器语言,所以全部的对象在编译时就必须有一个类型定义,编译器没有办法推断动态调度的成员,也就没有办法编译代码了。这一类语言通常被称为静态语言。.net
很长一段时间以来,这两类语言也都相安无事,本身管着本身的一亩三分地。然而,动态编程对程序员的诱惑实在是太大了,不少工程师就会想,咱们能不能让编译器经过某种方式编译动态调度的对象呢?答案是确定的。在.net CLR还不支持动态调度的时候,就已经有工程师经过CodeDom动态编译技术和反射模拟了动态调度类型。code
虽然这种方式性能十分差劲,用起来也十分的繁琐,但也为后来的动态基元类型的实现提供了理论基础。对象
咱们前面说了,动态语言是运行时编译的,因此才可以动态调度。因此咱们能够肯定如下几点:blog
1. 动态调度对象须要在运行时才能肯定其结构ip
2. 动态调度对象须要动态编译,不可以预编译
3. 经过动态编译和反射技术,咱们能够以一种丑陋的方式模拟动态调度的过程
因此,若是在JITCompiler中,对须要动态调度的对象进行动态编译不就可以在预编译语言中实现动态调度了吗?
在.net 4.0及以后的版本中,咱们能够这样写:
1 public void Main() 2 { 3 dynamic temp = new System.Dynamic.ExpandObject(); 4 temp.FuncA = () =>{ 5 Console.WriteLine("FuncA Involved"); 6 }; 7 temp.Name = "CSharp Dynamic Dispatch"; 8 }
当编译器编译到这段代码的时候,不会将其编译为机器码,而是在程序集中加入payload,并在运行到这里时调用.NET 编译器动态编译,获得当前的动态对象的实例,而后经过IL的内存操做访问其中的成员,使性能比反射高出不少,实现起来也更加优雅了。
说到这里咱们就可以得出结论,CLR版本4.0以后的C#已经符合全部动态语言的定义,能够被称为一种动态语言了。甚至若是你喜欢,能够彻底把C#当作动态语言来用,虽然可能在某些场景下会有必定的性能损失,但跟反射比起来,仍是会优秀不少的。