技术开发 频道

C# 4.0新特性

  运行时查找

  在运行时,动态操作将根据目标对象d的本质进行分派——

  COM对象

  如果d是一个COM对象,则操作通过COM IDispatch进行动态分派。这允许调用没有主互操作程序集(Primary Interop Assembly,PIA)的COM类型,并依赖C#中没有对应概念的COM特性,如索引属性和默认属性。

  动态对象

  如果d实现了IDynamicObject接口,则请求d自身来执行该操作。因此通过实现IDynamicObject接口,类型可以完全重新定义动态操作的意义。这在动态语言——如IronPython和IronRuby——中大量使用,用于实现他们的动态对象模型。API也会使用这类对象,例如HTML DOM允许直接使用属性语法来访问对象的属性。

  简单对象

  除此之外,则d是一个标准的.NET对象,操作是通过在其类型上进行反射来分派的,C#的“运行时绑定器(runtime binder)”实现了运行时的C#查找和重载解析。其背后的本质是将C#编译器作为运行时组件运行,来“完成”被静态编译器延迟的动态操作。

  示例

  考虑下面的代码——

dynamic d1 = new Foo();  
dynamic d2
= new Bar();  
string s;  
  
d1.M(s, d2,
3, null);  

 

    由于对M进行调用的接受者是dynamic类型的,C#编译器不会试图解析该调用的意义。而是将有关该调用的信息存储起来,供运行时使用。该信息(通常称作“有效载荷”)本质上等价于——

  “使用下面的参数执行一个称作M的实例方法——

  • 1. 一个string
  • 2. 一个dynamic
  • 3. 一个int字面值3
  • 4. 一个object字面值null

  在运行时,假设d1的实际类型Foo不是COM类型,也没有实现IDynamicObject。在这种情况下,C#运行时绑定器担负起了重载解析的工作,这是基于运行时类型信息完成的,按照下面的步骤进行处理——

  • 1. 使用反射获取两个对象d1d2的实际运行时类型,它们没有静态类型(包括静态类型dynamic)。结果为d1Foo类型而d2Bar
  • 2. 使用普通的C#语义在Foo类型上对M(string,Bar,3,null)调用进行方法查找和重载解析。
  • 3. 如果找到了该方法,则调用它;否则抛出运行时异常。

  带有动态参数的重载解析

  即便方法调用的接受者是静态类型的,重载解析依然发生在运行时。当一个或多个实参是dynamic类型时就会出现这种情况——

Foo foo = new Foo();  
dynamic d
= new Bar();  
  
var result
= foo.M(d);  

 

 

  C#运行时绑定器会基于d的运行时类型——也就是Bar——在FooM方法的静态可知(statically known)重载之间进行选择。其结果是dynamc类型。

  动态语言运行时

  动态语言运行时(Dynamic Language Runtime,DLR)是动态查找的底层实现的一个重要组件,也是.NET 4.0中新增的API。

  DLR不仅为C#动态查找,还为很多其他.NET上的动态语言——如IronPython和IronRuby——的实现提供了底层的基础设施。这一通用基础设施确保了高度的互操作性,更重要的是,DLR提供了卓越的缓存机制,使得运行时分派的效率得到巨大的改善。

  对于使用C#动态查找的用户来说,除了更高的性能之外,根本感觉不到DLR的存在。不过,如果你希望实现自己的动态分派对象,可以使用IDynamicObject接口来与DLR互操作,并向其中插入自己的行为。这是一个非常高级的任务,要求对DLR的内部工作原理有相当深入的了解。对于编写API的人,值得在这些问题上花些功夫,这样能够更广泛地改善可用性,例如为一个本身就是动态的领域编写类库。

0
相关文章