程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#dynamic關鍵字

C#dynamic關鍵字

編輯:C#入門知識

 

C#是一種類型安全的編程語言(所有表達式都能解析成某個類型的實例,在編譯器生成的代碼中,只會執行對這個類型有效的操作),和非類型安全的語言相比,類型安全的優勢就體現出來了:

 

1.許多錯誤能在編譯時檢測到,取保代碼在執行它之前是正確的。

 

2.編譯時語言通常能生成更小,更快的代碼。(在編譯時進行更多的假設,並在IL和元數據中落實那些假設)

 

 

 

為了方便開發人員使用反射或者與基本組件通信,dynamic誕生了!

 

一下代碼展示了如何利用反射在一個String目標("根據我找類型")上調用一個方法(“Contains”),向它傳遞一個實參(“我只是一個string參數”),並將結果存儲到局部變量result中。

 

 static void Main()        {            object target = "根據我找類型";            object arg = "我只是個string參數";            Type[] argtype = new Type[] { arg.GetType()};            System.Reflection.MethodInfo method = target.GetType().GetMethod("Contains", argtype);            object[] argm = new object[] { arg};            Boolean result=Convert.ToBoolean(method.Invoke(target,argm));} 

現在,有了dynamic!

 

 

static void Main()        {            dynamic target = "根據我找類型";            dynamic arg = "參數";            Boolean result = target.Contains(arg);}

 

 

是不是發現有了顯著的簡化。

 

 static void Main()        {            Application excel = new Application();            excel.Visible = true;            excel.Workbooks.Add(Type.Missing);            ((Range)excel.Cells[1, 1]).Value = "放入單元格的字符";//如果沒有dynamic類型,excel.Cells[1,1]的返回值是objec類型,必須先把它轉換為Rang類型才能訪問Value屬性。            excel.Cells[1, 1].Value = "放入單元格的字符";//為COM對象生成一個可由“運行時”調用的包裝程序集時,COM方法中使用的任何variant實際都會被轉換為dynamic,這稱為動態化(dynamicfication)。            //所以這裡excel.Cells[1,1]是dynamic類型,可以不必顯示把它轉換成Range類型也能訪問它的Value。動態化顯著簡化了與COM對象的互操作。        }

 

 

看到了dynamic的神奇,那再讓我們刨根問底吧。

 

我們可以用dynamic表達式或變量調用一個成員,比如字段,屬性/索引器,方法,委托,以及一元/二元/轉換操作符,當我們的代碼使用dynamic表達式或變量調用一個成員時,編譯器會生成特殊的IL代碼來描述所需的操作。

 

這種特殊的代碼稱為payload(有效載荷)(這些payload代碼使用了一個稱為運行時綁定器(runtime binder)的類),在運行時,payload代碼根據當前由dynamic表達式/變量引用的對象的實際類型來決定具體的操作。

 

看這個例子:

 

        static void Main()        {            for (int i = 0; i < 2; i++)            {                dynamic arg = (i == 0) ? (dynamic)10 : "A";                dynamic result = plus(arg);//第一次循環i==0 ,arg=10;所以調用plus時,返回的是int類型。第二次是string類型。                M(result);//payload代碼判斷出傳給M的值的實際類型,然後調用相應的重載方法。            }          Console.ReadKey();        }        static dynamic plus(dynamic arg) { return arg+arg;}        static  void M(int n) { Console.WriteLine("M(int):{0}", n); }       static void M(string s) { Console.WriteLine("M(string):{0}", s); }    }

 

 

在字段類型,方法參數類型或方法類型被指定為dynamic的前提下,編譯器會將這個類型轉換為System.Object,並在元數據中向字段,參數或者返回類型應用System.Runtime.CompilerSevices.DynamicAttribute的一個實例。如果是一個局部變量被指定為dynamic,變量類型也會成為Object,但不會向局部變量應用DynamicAttribute,應為它的使用限制在方法之內。

 

由於dynamic就是object 所以不僅僅將dynamic變成object,或者object變成dynamic就獲取兩個不同的方法簽名。例子:

 

  object dd(dynamic i) { return i; } dynamic dd( object i) {return i; }

這就通不過編譯。

 

dynam的類型轉換:

 

 static void Main()        {            object o = 123;//(裝箱)            Int32 n = o;//錯誤!不允許從object到int32的隱式轉換。            Int32 n1 = (Int32)o;//從object顯示轉換到int32。(拆箱)            dynamic od = 123;//(裝箱)            dynamic os = "dsfsdf";            Int32 ns = os;//運行時報錯。            Int32 nd = od;//從dynamic隱式轉換為int32(拆箱)            //在本例中可看出,dynamic轉為其他類型時,允許省略顯示轉型。            //但是CLR會在運行時驗證轉型,確保類型安全。如果對象類型不兼容要轉換成的類型,clr就會拋出一個InvalidCastException異常。        }

dynamic和var的區別:

 

1.var聲明一個局部變量只是一種簡化語法,它要求編譯器根據一個表達式推斷具體的數據類型。

 

2.var只能用於聲明方法內部的局部變量,而dynamic可用於局部變量,字段,參數。

 

3.表達式不能轉型為var,但能轉型為dynamic。

 

4.必須顯式初始化用var聲明的變量,但無需初始化用dynam聲明的變量。

 

使用dynamic應注意:

 

在運行時,Microsoft.Csharp.dll必須加載到AppDomain中,這回損害程序性能,並增大內錯耗用,Microsoft.Csharp.dll還會加載System.dll和System.Core.dll,如果使用dynamic與COM組件互操作,還會加載System.Dynamic.dll,payload代碼執行時會在運行時生成動態代碼。這些代碼會進入一個駐留在內存的程序集,稱為“匿名寄宿的DynamicMethods程序集”(Anonymously Hosted DynamicMethods Assembly).

 

當一個特性的調用使用具有相同運行時類型的dynamic實參發出了大量調用時,這個代碼可以增強調度的性能。

 

雖然dynamic能簡化語法,但是動態求值功能產生的額外開銷也是不容忽視的,畢竟加載所有這些程序集以及額外的內存消耗,會對性能產生額外的影響。如果程序中只是一兩個地方需要動態行為,或許傳統的做法會更加高效

 

摘自 小白

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved