欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# 反射與dynamic最佳組合示例代碼

 更新時間:2017年09月06日 15:26:07   作者:DW039  
這篇文章主要介紹了C# 反射與dynamic最佳組合示例代碼,需要的朋友可以參考下

在 C# 中反射技術(shù)應(yīng)用廣泛,至于什么是反射.........你如果不了解的話,請看下段說明,否則請?zhí)^下段。廣告一下:喜歡我文章的朋友請關(guān)注一下我的blog,這也有助于提高本人寫作的動力。

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

個人認(rèn)為反射最突出的優(yōu)點(diǎn)或存在的合理性:在不修改程序原碼的情況下,實(shí)現(xiàn)程序功能的動態(tài)調(diào)整(Runtime動態(tài)對象創(chuàng)建)

示例:

 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來執(zhí)行,有時需要是Car有時需要Person。常見的解決方案是添加 if 等判斷結(jié)構(gòu),如下:

 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();
  }

這種結(jié)構(gòu)確是解決了現(xiàn)在的需求,但并不健壯。隨著 IRun 接口實(shí)現(xiàn)、相關(guān)類的繼承的增加,上面的判斷結(jié)構(gòu)也會飛速增長。面向?qū)ο缶幊?、設(shè)計(jì)模式均遵循的一大原則就是封裝變換,所以上面的程序無法很好的應(yīng)對變化。在此我們并不涉及 “設(shè)計(jì)模式的” 的知識,因此下面的示例代碼只為簡化上面的程序、并未刻意套用設(shè)計(jì)模式相關(guān)知識。如下:     

 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();
  }

經(jīng)過上面的修改,程序可自行根據(jù)用戶的輸入,通過Activator.CreateInstance創(chuàng)建 IRun 的實(shí)例,程序此處不會再隨 IRun 的實(shí)現(xiàn)者增多這種問題的影響而發(fā)生變化。上面的這種優(yōu)點(diǎn)就是通過反射得到的,也是我所認(rèn)為的“反射存在的合理性”。

Activator、Assembly 實(shí)現(xiàn)反射方式創(chuàng)建對象

C#中反射方式創(chuàng)建對象可以通過 Activator.CreateInstance(靜態(tài))和 Assembly.CreateInstance(非靜態(tài))來實(shí)現(xiàn),其中Assembly.CreateInstance 內(nèi)部調(diào)用的仍是Activator.CreateInstance。

根據(jù)要動態(tài)創(chuàng)建的類型對象是否處于當(dāng)前程序集之中,可將反射創(chuàng)建對象分為:創(chuàng)建程序集內(nèi)的類型對象與創(chuàng)建程序集外的類型對象。

創(chuàng)建程序集內(nèi)的類型對象

  private static void ReflectionIRun1(string className)
  {
   string classPath = String.Format("namespace.{0}", className);
   //參數(shù) null ,指出所要創(chuàng)建類型對象位于當(dāng)前程序集 
   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());
  }

創(chuàng)建程序集外的類型對象

項(xiàng)目中增加一個 類庫 (另一個程序集),如下圖:

添加一個 Boss 類,如下:

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

獲取 一個 Boss 對象前,首先添加對 Lib 的引用,獲取示例如下:

 private static void ReflectionBoss1()
  {
   string classPath ="Lib.Boss";
   //"Lib" 參數(shù)指明要加載的程序集(即要創(chuàng)建的對象類型在哪個程序集中定義)
   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") 加載的程序集(即要創(chuàng)建的對象類型在哪個程序集中定義)
   var assembly = Assembly.Load("Lib");
   Boss b = (Boss)assembly.CreateInstance(classPath);
   Console.WriteLine(b.Talk());
  } 

關(guān)于反射時CLR如何查找并定位要加載的程序集,請參考MSDN中關(guān)于反射相關(guān)的知識。

反射訪問字段、調(diào)用方法(屬性)

反射除可以幫我們動態(tài)創(chuàng)建對象外,還可幫我們動態(tài)訪問對象的方法(屬性)或字段,因 C# 版本不同具體方法會有變更或擴(kuò)展,更深入內(nèi)容請參考MSDN。下面僅作簡單示例(標(biāo)準(zhǔn)用法)。

給老板改名,示例:      

 private static void ReflectionBoss1()
  {
   string classPath = "Lib.Boss";
   //"Lib" 參數(shù)指明要加載的程序集(即要創(chuàng)建的對象類型在哪個程序集中定義)
   var handler = Activator.CreateInstance("Lib", classPath);
   Boss b = handler.Unwrap() as Boss;
   //關(guān)鍵代碼
   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" 參數(shù)指明要加載的程序集(即要創(chuàng)建的對象類型在哪個程序集中定義)
   var handler = Activator.CreateInstance("Lib", classPath);
   Boss b = handler.Unwrap() as Boss;
   //關(guān)鍵代碼
   MethodInfo method = b.GetType().GetMethod("Payfor", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance);
   object money = method.Invoke(b, new object[] { 10 });
   Console.WriteLine("DW039:老大給我報(bào)銷10元錢車費(fèi)......");
   Console.WriteLine("{0}:.....,算不清了,給你這些吧。",b.Name);
   Console.WriteLine("DW039:......");
   Console.WriteLine("{0}:{1}", b.Name,money);
   Console.WriteLine("DW039:老大你真棒!");
  }

輸出:

dynamic 與 反射 雙劍合璧

因?yàn)榉瓷涫沁\(yùn)行時的類型操作,所以在編程時面臨類型不確定的問題。根據(jù)上一篇《C# 匿名對象(匿名類型)、var、動態(tài)類型 dynamic》講得 dynamic 動態(tài)類型結(jié)合我們編寫的反射程序,可以大大優(yōu)化程序邏輯(訪問受保護(hù)級別限制的代碼不在此范圍內(nèi))。

上面代碼的優(yōu)化:

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 動態(tài)類型對象 b 來調(diào)用反射得到對象的屬性、方法可直接調(diào)用,從而省去了頻繁的類型轉(zhuǎn)換操作。

反射常見應(yīng)用場景

應(yīng)用場景我印象最深刻的是 MS Petshop 示例,從SQL Server 數(shù)據(jù)庫切換到 oracle 數(shù)據(jù)庫時反射獲得不同的數(shù)據(jù)訪問層。然我實(shí)際項(xiàng)目中從未遇到過中途切換數(shù)據(jù)庫的情況,其他應(yīng)用場景基本類似上面的示例。如果朋友你發(fā)現(xiàn)更多的應(yīng)用場景,請給予補(bǔ)充,3ks。

反射的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):反射使程序更靈活

缺點(diǎn):反射運(yùn)行速度相對較慢

至于反射相比普通程序慢,我沒有進(jìn)行過測試也不打算進(jìn)行?,F(xiàn)實(shí)情況是:Ms提倡使用 dynamic、Mvc流行、Ms對CLR不斷優(yōu)化、機(jī)器性能的提升,所以你在開發(fā)中無需過多考慮反射的性能問題。如果你寫的程序運(yùn)行速度出現(xiàn)了瓶頸(應(yīng)首先確保自己程序?qū)懙暮侠恚?,研究一下?shù)據(jù)庫優(yōu)化、數(shù)據(jù)緩存、web緩存、負(fù)載均衡等技術(shù)我認(rèn)為更實(shí)際一些。

相關(guān)文章

  • C#程序中使用LINQ to XML來查詢XML格式數(shù)據(jù)的實(shí)例

    C#程序中使用LINQ to XML來查詢XML格式數(shù)據(jù)的實(shí)例

    這篇文章主要介紹了C#程序中使用LINQ to XML來查詢XML格式數(shù)據(jù)的實(shí)例,LINQ to XML是.NET框架中集成的接口,可以將XML數(shù)據(jù)放到內(nèi)存中進(jìn)行處理,需要的朋友可以參考下
    2016-03-03
  • C#通過Builder模式造車

    C#通過Builder模式造車

    這篇文章介紹了C#通過Builder模式造車的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10
  • C#中事務(wù)處理和非事務(wù)處理方法實(shí)例分析

    C#中事務(wù)處理和非事務(wù)處理方法實(shí)例分析

    這篇文章主要介紹了C#中事務(wù)處理和非事務(wù)處理方法,較為詳細(xì)的分析了C#中事務(wù)處理與非事務(wù)處理的使用技巧,對于使用C#進(jìn)行數(shù)據(jù)庫程序開發(fā)有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • C#區(qū)分中英文按照指定長度截取字符串的方法

    C#區(qū)分中英文按照指定長度截取字符串的方法

    這篇文章主要介紹了C#區(qū)分中英文按照指定長度截取字符串的方法,涉及C#操作字符串的正則匹配與截取等常用操作技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-03-03
  • C#中File和FileStream的簡單介紹和用法

    C#中File和FileStream的簡單介紹和用法

    這篇文章主要給大家介紹了關(guān)于C#中File和FileStream用法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • WPF實(shí)現(xiàn)自定義Panel面板的示例詳解

    WPF實(shí)現(xiàn)自定義Panel面板的示例詳解

    WPF中的Panel(面板),是繼承自FrameworkElement的抽象類,表示一個可以用來排列子元素的面板,本文主要來和大家聊聊WPF如何實(shí)現(xiàn)自定義Panel,感興趣的可以了解下
    2023-09-09
  • 淺拷貝和深拷貝深入理解(shallow copy VS deep copy)

    淺拷貝和深拷貝深入理解(shallow copy VS deep copy)

    淺拷貝和深拷貝深入理解(shallow copy VS deep copy) 本文重點(diǎn)討論引用類型變量的拷貝機(jī)制和實(shí)現(xiàn)
    2014-01-01
  • C#文件上傳與下載的實(shí)現(xiàn)方法

    C#文件上傳與下載的實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了C#文件上傳與下載的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • C#中使用FilleStream實(shí)現(xiàn)視頻文件的復(fù)制功能

    C#中使用FilleStream實(shí)現(xiàn)視頻文件的復(fù)制功能

    這篇文章主要介紹了C#中使用FilleStream實(shí)現(xiàn)視頻文件的復(fù)制功能,本文通過實(shí)例代碼給大家介紹的非常想詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • C#訪問命令行的兩種方法

    C#訪問命令行的兩種方法

    這篇文章主要介紹了C#訪問命令行的兩種方法,實(shí)例分析了C#操作命令行的兩種常用技巧,需要的朋友可以參考下
    2015-06-06

最新評論