技术开发 频道

C#4.0新特性之动态查找

      【IT168 技术文档】在大神Anders的领导下,C#这门语言也越来越快地朝着编程语言宇宙第一神器进化,C#4.0的新特征都是围绕“动态”(dynamic)的概念的,本文我们先来看看第一个新特性:动态查找(Dynamic Lookup)。

  1.初识dynamic

  动态查找允许动态(即在运行时)实现对某个对象的操作与对象类型的绑定,而不管这个对象是来自COM,IronPython,HTML DOM还是CLR的反射。你可以在程序中绕过编译器的类型检查,而把类型的匹配(lookup)丢给运行时去作。如果你需要对这样的对象进行操作,则会用到一个全新的类型:dynamic

  dynamic是一个和之前所有CTS支持的类型都很不一样的类型,因为他不是object!确切的说,它会告知编译器“请暂时别把我当成任何object!”。看上去这和过去的反射很类似,但是dynamic可以让我们在代码里就可以直接实现对这个未知类型对象的操作,下面我们通过一个例子来说明dynamic带来的便利。我的电脑上安装了一种叫X雷的下载软件,它提供了一些COM组件可供调用,在过去,我需要这样来调用这个COM对象:

 without Dynamic
  
private static void NoDynamicCall(String url = "http://www.sunhao.cc/temp/lgxz.wma")
  {
  Type thunderAgent;
  
object objThunderAgent;
  
object[] parameter = new object[14];
  
if (url != null && url.Length > 0)
  {
  thunderAgent
= Type.GetTypeFromProgID("ThunderAgent.Agent");
  objThunderAgent
= Activator.CreateInstance(thunderAgent);
  parameter[
0] = url;//url
  parameter[
1] = "";
  parameter[
2] = "";
  parameter[
3] = "";
  parameter[
4] = url;//ref url
  parameter[
5] = -1;
  parameter[
6] = 0;
  parameter[
7] = -1;//threadCount
  parameter[
8] = "";//strCookie
  parameter[
9] = "";
  parameter[
10] = "";
  parameter[
11] = 1;
  parameter[
12] = "";
  parameter[
13] = -1;
  thunderAgent.InvokeMember(
"AddTask5", BindingFlags.InvokeMethod, null, objThunderAgent, parameter);
  
object[] parm = new object[1] { 1 };
  thunderAgent.InvokeMember(
"CommitTasks2", BindingFlags.InvokeMethod, null, objThunderAgent, parm);
  }
  }

 

  这种通过Type.InvokeMemer在COM对象上调用方法实属别扭且无奈之举,因为编译器要先对方法的调用者进行类型绑定。不过现在有了dynamic类型,我们可以按照这样的方式对上述com对象进行操作:

with Dynamic
  Type agentType;
  
if (url != null && url.Length > 0)
  {
  agentType
= Type.GetTypeFromProgID("ThunderAgent.Agent");
  dynamic dAgent
= Activator.CreateInstance(agentType);
  dAgent.AddTask5(url,
"", "", "", url, -1, 0, -1, "","", "", 1, "", -1);
  dAgent.CommitTasks2(
1);
  }

 
   这样直接的调用方式要自然多了。不过你也许会问,既然这里的dAgent的类型未知,而其AddTask5方法在编译时也完全不知道其存在性,那么岂不是任何合法或者非法的调用都不会受到编译器的监管,而把一切可能的危险留给了运行时?的确,编译器只会检查发生在CTS支持的各种类型上的调用,而dynamic在编译时还没有被映射到任何一种CTS类型。

  Tips 前面说的dynamic不是object句话当且仅当程序运行前是正确的,运行时dynamic会首先被声明成为一个object,下面是IL描述的分配本地参数的stack上的信息:


      dynamic IL
  .method
private hidebysig static void DynamicCall([opt] string url) cil managed
  {
  .param [
1] = "http://www.sunhao.cc/temp/lgxz.wma"
  
// Code size 420 (0x1a4)
  .maxstack
17
  .locals init ([
0] class [mscorlib]System.Type agentType,
  [
1] object dAgent,
  [
2] bool CS$4$0000,
  [
3] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0001)
  
//以下省略N行

 
  而编译器对任何对发生在dynamic类型上的操作无能为力,他能做的唯一工作就是为运行时收集一些该dynamic对象的信息,比如它上面的方法签名。dynamic提供了访问com对象的方便,但是由于它在一定程度上破坏了C#强类型的特性,同时也要求程序员对自己写下的代码完全负责,增加了debug的成本。所以说dynamic有风险,使用需谨慎。

0
相关文章