C#4.0新特性之(一)動態尋找

來源:互聯網
上載者:User

 C#4.0新特性之(一)動態尋找

 

  在大神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有風險,使用需謹慎。

2.DLR與自訂動態類型

  Dynamic Language Runtime是.Net 4.0中一組全新的API。對於C#,DLR提供了Microsoft.CSharp.RuntimeBinder命名空間[1],它為C#提供了強大的運行時互操作(COM,Ironpython等)能力,DLR也有優秀的緩衝機制,對象一旦被成功綁定,CLR在下一次調用的時候就可以直接對確定類型的對象進行操作,而不必再通過DLR去lookup了。如果想在自己的代碼中實現一個動態類型對象,可以繼承DynamicObject[2]類,並實現自己的若干get和set方法。例如下面這個簡單的例子:

MyClass

   public class MyClass:DynamicObject
    {
       public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
       {
           result =  binder.Name;
           return true; 
       }
    }

上述代碼在嘗試invoke某個方法的時候直接返回該方法的名字。於是下面的代碼將輸出方法名:

代碼

            dynamic d = new MyClass();
            Console.WriteLine(d.AnyMember());

 

3.dynamic的使用

  由於dynamic本身也是一個類型(雖然只有編譯器認識它,運行時不認識它),而且dynamic實現了implicit和explicit運算子,理論上任何可以使用CLR的類型的地方都可以用dynamic。以下的代碼是合法的:

dynamic use case

            dynamic d = (dynamic)2;
            Action<dynamic> dAct = new Action<dynamic>((dynamic n) => { Console.Write(n.GetType()+": "+n); });
            dAct(d);

  但是dynamic也不是萬能的:

  1).目前動態尋找不支援擴充方法的調用(可能在未來的版本的C#中會提供支援)。

  2).匿名方法和Lambda運算式不能轉換為dynamic,也就是說dynamic d = x=>x;是不合法的,事實上lambda運算式也不能轉成object。一樣的道理,因為lambda運算式會在上下文環境下要麼被編譯器解釋成委託類型,要麼被解釋成運算式樹狀架構,但是如果上下文缺乏類型資訊,編譯器會confuse掉。

4.總結

  dynamic是C#4.0的核心特徵,感覺上是C#這種強型別的語言多了一些動態語言的特徵,是對C#和.Net的一個完善。如本文開頭所說,作為一門程式設計語言,C#正在猛練北冥神功[3] ,這樣下去可能C#要和ms word一樣成為居家旅行殺人越貨必備的武器了。

5.引用

[1] http://msdn.microsoft.com/en-us/library/microsoft.csharp.runtimebinder(VS.100).aspx

[2] http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject(VS.100).aspx

[3] http://baike.baidu.com/view/146278.htm 

Author:Freesc Huang @ CNBlogs

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.