C# dynamic關鍵字的使用方法

來源:互聯網
上載者:User

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 = http://www.jb51.net/smailxiaobai/archive/2011/11/25/"放入儲存格的字元";//如果沒有dynamic類型,excel.Cells[1,1]的傳回值是objec類型,必須先把它轉換為Rang類型才能訪問Value屬性。
excel.Cells[1, 1].Value = http://www.jb51.net/smailxiaobai/archive/2011/11/25/"放入儲存格的字元";//為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能簡化文法,但是動態求值功能產生的額外開銷也是不容忽視的,畢竟載入所有這些程式集以及額外的記憶體消耗,會對效能產生額外的影響。如果程式中只是一兩個地方需要動態行為,或許傳統的做法會更加高效。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.