C#中關於反射和dynamic最佳組合的樣本分享

來源:互聯網
上載者:User
這篇文章主要介紹了C# 反射與dynamic最佳組合範例程式碼,需要的朋友可以參考下

在 C# 中反射技術應用廣泛,至於什麼是反射.........你如果不瞭解的話,請看下段說明,否則請跳過下段。廣告一下:喜歡我文章的朋友請關注一下我的blog,這也有助於提高本人寫作的動力。

反射:當你背對一個美女或帥哥卻不能回頭仔細觀察研究時(純屬虛構,如有巧合、純屬雷同),一面小鏡子就能滿足你的需求。在 C# 編程過程中也經常遇到類似的情況:有一個別人寫的 dll 類庫你想使用卻沒程式文檔資料......此時通過 C# Runtime 提供的功能,你可以把該 dll 類庫載入到你的程式中,並細細研究 dll 的每一部分內容,這就是 C# 中的反射。

個人認為反射最突出的優點或存在的合理性:在不修改程式原碼的情況下,實現程式功能的動態調整(Runtime動態對象建立)

樣本:


 interface IRun {  void Run(); } class Person : IRun {  public void Run()  {   Console.WriteLine("走,去LOL啊!");  } } class Car : IRun {  public void Run()  {   Console.WriteLine("嗚...........");  } } class Program {  static void Main(string[] args)  {   IRun e = new Person();   e.Run();   Console.ReadLine();  } }

如果將上面的Run功能並不一定是由Person來執行,有時需要是Car有時需要Person。常見的解決方案是添加 if 等判斷結構,如下:


 static void Main(string[] args)  {   Console.WriteLine("請輸入:Car或Person");   string type = Console.ReadLine();   IRun e = null;   if ("Car" == type)   {    e = new Car();   }else if("Person" == type)   {    e = new Person();   }   if(null != e)    e.Run();   Console.ReadLine();  }

這種結構確是解決了現在的需求,但並不健壯。隨著 IRun 介面實現、相關類的繼承的增加,上面的判斷結構也會飛速增長。物件導向編程、設計模式均遵循的一大原則就是封裝變換,所以上面的程式無法很好的應對變化。在此我們並不涉及 “設計模式的” 的知識,因此下面的範例程式碼只為簡化上面的程式、並未刻意套用設計模式相關知識。如下:


 static void Main(string[] args)  {   Console.WriteLine("請輸入:Car或Person");   string type = Console.ReadLine();   string classPath = String.Format("namespace.{0}", type);   IRun e = Activator.CreateInstance(null, classPath).Unwrap() as IRun;   if(null != e)    e.Run();   Console.ReadLine();  }

經過上面的修改,程式可自行根據使用者的輸入,通過Activator.CreateInstance建立 IRun 的執行個體,程式此處不會再隨 IRun 的實現者增多這種問題的影響而發生變化。上面的這種優點就是通過反射得到的,也是我所認為的“反射存在的合理性”。

Activator、Assembly 實現反射方式建立對象

C#中反射方式建立對象可以通過 Activator.CreateInstance(靜態)和 Assembly.CreateInstance(非靜態)來實現,其中Assembly.CreateInstance 內部調用的仍是Activator.CreateInstance。

根據要動態建立的類型對象是否處於當前程式集之中,可將反射建立對象分為:建立程式集內的類型對象與建立程式集外的類型對象。

建立程式集內的類型對象


  private static void ReflectionIRun1(string className)  {   string classPath = String.Format("namespace.{0}", className);   //參數 null ,指出所要建立類型對象位於當前程式集    var handler = Activator.CreateInstance(null, classPath);   IRun e = (IRun)handler.Unwrap();   Console.WriteLine(e.Run());  }  private static void ReflectionIRun2(string className)  {   string classPath = String.Format("namespace.{0}", className);   //typeof(IRun).Assembly 擷取 IRun 類型所在的程式集   object obj = typeof(IRun).Assembly.CreateInstance(null, classPath);   IRun e = (IRun)obj;   Console.WriteLine(e.Run());  }

建立程式集外的類型對象

項目中增加一個 類庫 (另一個程式集),如:

添加一個 Boss 類,如下:


namespace Lib{ public class Boss {  private string name = "老大";    public string Name{   get {return name;}  }  public string Talk()  {   return "你們都被開除了......";  }  //老闆不會算賬,總是多付錢,所以很有自知之明的將Payfor設為private,防止外部人員調用  private int Payfor(int total)  {   return total + 10;  } }}

擷取 一個 Boss 對象前,首先添加對 Lib 的引用,擷取樣本如下:


 private static void ReflectionBoss1()  {   string classPath ="Lib.Boss";   //"Lib" 參數指明要載入的程式集(即要建立的物件類型在哪個程式集中定義)   var handler = Activator.CreateInstance("Lib", classPath);   Boss b = handler.Unwrap() as Boss;   Console.WriteLine(b.Talk());  }  private static void ReflectionBoss2()  {   string classPath ="Lib.Boss";   //Assembly.Load("Lib") 載入的程式集(即要建立的物件類型在哪個程式集中定義)   var assembly = Assembly.Load("Lib");   Boss b = (Boss)assembly.CreateInstance(classPath);   Console.WriteLine(b.Talk());  }

關於反射時CLR如何尋找並定位要載入的程式集,請參考MSDN中關於反射相關的知識。

反射訪問欄位、調用方法(屬性)

反射除可以幫我們動態建立對象外,還可幫我們動態訪問對象的方法(屬性)或欄位,因 C# 版本不同具體方法會有變更或擴充,更深入內容請參考MSDN。下面僅作簡單樣本(標準用法)。

給老闆改名,樣本:


 private static void ReflectionBoss1()  {   string classPath = "Lib.Boss";   //"Lib" 參數指明要載入的程式集(即要建立的物件類型在哪個程式集中定義)   var handler = Activator.CreateInstance("Lib", classPath);   Boss b = handler.Unwrap() as Boss;   //關鍵代碼   FieldInfo f = b.GetType().GetField("name", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);   f.SetValue(b, "小二");   Console.WriteLine("{0}:{1}", b.Name, b.Talk());  }

輸出:

讓老闆付錢:


private static void ReflectionBoss1()  {   string classPath = "Lib.Boss";   //"Lib" 參數指明要載入的程式集(即要建立的物件類型在哪個程式集中定義)   var handler = Activator.CreateInstance("Lib", classPath);   Boss b = handler.Unwrap() as Boss;   //關鍵代碼   MethodInfo method = b.GetType().GetMethod("Payfor", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance);   object money = method.Invoke(b, new object[] { 10 });   Console.WriteLine("DW039:老大給我報銷10元錢車費......");   Console.WriteLine("{0}:.....,算不清了,給你這些吧。",b.Name);   Console.WriteLine("DW039:......");   Console.WriteLine("{0}:{1}", b.Name,money);   Console.WriteLine("DW039:老大你真棒!");  }

輸出:

dynamic 與 反射 雙劍合璧

因為反射是運行時的類型操作,所以在編程時面臨類型不確定的問題。根據上一篇《C# 匿名對象(匿名型別)、var、動態類型 dynamic》講得 dynamic 動態類型結合我們編寫的反射程式,可以大大最佳化程式邏輯(訪問受保護層級限制的代碼不在此範圍內)。

上面代碼的最佳化:


private static void ReflectionBoss1()  {   string classPath ="Lib.Boss";   var handler = Activator.CreateInstance("Lib", classPath);   dynamic b = handler.Unwrap();   Console.WriteLine(b.Talk());  }  private static void ReflectionBoss2()  {   string classPath ="Lib.Boss";   var assembly = Assembly.Load("Lib");   dynamic b = assembly.CreateInstance(classPath);   Console.WriteLine(b.Talk());  }

通過 dynamic 動態類型對象 b 來調用反射得到對象的屬性、方法可直接調用,從而省去了頻繁的類型轉換操作。

反射常見應用情境

應用情境我印象最深刻的是 MS Petshop 樣本,從SQL Server 資料庫切換到 oracle 資料庫時反射獲得不同的資料訪問層。然我實際項目中從未遇到過中途切換資料庫的情況,其他應用情境基本類似上面的樣本。如果朋友你發現更多的應用情境,請給予補充,3ks。

反射的優缺點

優點:反射使程式更靈活

缺點:反射運行速度相對較慢

至於反射相比普通程式慢,我沒有進行過測試也不打算進行。現實情況是:Ms提倡使用 dynamic、Mvc流行、Ms對CLR不斷最佳化、機器效能的提升,所以你在開發中無需過多考慮反射的效能問題。如果你寫的程式運行速度出現了瓶頸(應首先確保自己程式寫的合理),研究一下資料庫最佳化、資料緩衝、web緩衝、負載平衡等技術我認為更實際一些。

相關文章

聯繫我們

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