日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

什么是反射

發(fā)布時間:2024/6/21 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 什么是反射 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

反射總結(jié)目錄

什么是反射

程序運行時將exe、dll文件加載到內(nèi)存并執(zhí)行一些操作的過程,這個過程稱為反射。

通常所說的反射是實現(xiàn)這個過程所使用的技術手段,.Net中System.Reflection等命名空間提供了反射的實現(xiàn)。

反射的原理

通過對程序集元數(shù)據(jù)的搜索找到對應的成員類型并使用,以實現(xiàn)驗證或動態(tài)調(diào)用程序集的目的。

一個簡單的例子引入反射

下面這簡單例子引入反射的使用,這個例子中定義了一個Hello類并添加一個Say方法,我將使用反射調(diào)用Say方法。

namespace ReflectionStudy {public class Hello{public void Say(){Console.WriteLine("Hello Reflection!");}} }//使用反射技術調(diào)用Say方法 //1.從當前程序集中查找Hello類 var helloType= Assembly.GetExecutingAssembly().GetType("ReflectionStudy.Hello"); //2.獲取Hello類的Say方法 var method = helloType.GetMethod("Say"); //3.創(chuàng)建Hello類的實例 var helloInstance=Activator.CreateInstance(helloType); //4.執(zhí)行Say方法 method.Invoke(helloInstance, null);

System.Reflection命名空間

上面的例子雖然簡單,但是已足夠說明反射的大致流程:

  • 首先加載程序集
  • 在程序集中查找我們需要的類(發(fā)現(xiàn)類型)
  • 生成類實例
  • 找到我們需要使用的MethodInfo,FiledInfo,PropertyInfo,EventInfo等成員類型
  • 最后就是執(zhí)行我們要執(zhí)行的動作
  • 1. 加載程序集

    因為程序集是個比較大的概念,而這偏離了這篇文章的主題,請移步我的另一篇文章《程序集》。

    2. 發(fā)現(xiàn)類型

    FCL提供了許多API來獲取程序集中的類型,目前常用的API是Assembly中的ExportedTypes、DefinedTypes、GetType等,ExportedTypes屬性用來獲取公開方法即public類型,DefiedTypes屬性用來獲取所有類型,GetType方法獲取一個指定的類型。

    var assembly = Assembly.Load(@"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); int index=0; Console.WriteLine("獲取程序集:{0} 中的ExportedTypes",assembly); foreach (var type in assembly.ExportedTypes) {Console.WriteLine("{0}. {1}", ++index,type); } Console.WriteLine("ExportedTypes類型有{0}個",assembly.ExportedTypes.Count()); index = 0; Console.WriteLine("獲取程序集:{0} 中的DefinedTypes", assembly); foreach (var type in assembly.DefinedTypes) {Console.WriteLine("{0}. {1}", ++index, type); } Console.WriteLine("DefinedTypes類型有{0}個", assembly.ExportedTypes.Count());

    3. 構(gòu)造類型實例

    在FCL中提供了幾個構(gòu)造類型實例的機制分散在System.Activator,System.AppDomain,System.Reflection.ConstructorInfo中,如果查看源碼的話可以看到內(nèi)部實現(xiàn)調(diào)用的都是Activator.CreateInstance。

    下面的例子演示實例的創(chuàng)建 public class Hello {public void Say(){Console.WriteLine("Hello Reflectioin!");} } //出于演示的目的下面這句簡化了加載程序集的步驟 Type helloType = typeof(Hello); //創(chuàng)建實例 var hello=Activator.CreateInstance(helloType);

    4. 發(fā)現(xiàn)類型成員

    在FCL中有反射提供了一個類型基類System.Reflection.MemberInfo,其派生類如下圖所示:

    通常使用Type類型來發(fā)現(xiàn)成員類型如:Method,Filed,Property,Event等。
    .Net 4中可以通過Type.GetTypeInfo擴展方法獲取TypeInfo對象以便獲取更多功能,相比Type類型TypeInfo代價更高。

    下面通過例子來說明如何發(fā)現(xiàn)成員:

    成員類型描述: * 一個事件OnSay * 兩個字段,_name是private,Age是Public * 一個Name屬性 * 三個方法,SayHello是Static public,Say是public,HaHa是private using System;namespace ReflectionAssembly {public class Hello{//事件public event Action OnSay;//私有字段private string _name;//共有字段public string Age;//屬性public string Name{get{return _name;}set{_name = value;}}//靜態(tài)方法public static void SayHello(){Console.WriteLine("SayHello");}//實例方法public void Say(){Console.WriteLine("Hello Reflectioin!");}//測試事件public void TestEvent(){if (OnSay != null){Console.WriteLine($"OnSay綁定了{OnSay.GetInvocationList().Length}個方法");//遍歷執(zhí)行綁定的事件foreach (Action onSay in OnSay.GetInvocationList()){onSay();}}}//私有實例方法void HaHa(){Console.WriteLine("HaHa");}} }

    因為MemberInfo是所有成員類型的基類,那么我們先看一下獲取所有的成員類型:

    static void Main(string[] args) {var helloType = Assembly.Load("ReflectionAssembly").GetType("ReflectionAssembly.Hello");var memberInfos = helloType.GetMembers();foreach (var memberInfo in memberInfos){Console.WriteLine($"成員類型:{memberInfo.MemberType}\t類型名稱:{memberInfo.Name}");}Console.WriteLine($"類型{helloType.FullName}共{memberInfos.Count()}個成員");Console.Read(); }//運行結(jié)果如下: 成員類型:Method 類型名稱:add_OnSay 成員類型:Method 類型名稱:remove_OnSay 成員類型:Method 類型名稱:get_Name 成員類型:Method 類型名稱:set_Name 成員類型:Method 類型名稱:SayHello 成員類型:Method 類型名稱:Say 成員類型:Method 類型名稱:ToString 成員類型:Method 類型名稱:Equals 成員類型:Method 類型名稱:GetHashCode 成員類型:Method 類型名稱:GetType 成員類型:Constructor 類型名稱:.ctor 成員類型:Property 類型名稱:Name 成員類型:Event 類型名稱:OnSay 成員類型:Field 類型名稱:Age 類型ReflectionAssembly.Hello共14個成員

    Why?我們只定義了7個成員,結(jié)果卻顯示14個?

    • 如果你了解Event類型那么可以忽略add_OnSay,remove_OnSay?!妒录臀袑W習總結(jié)》
    • 如果你了解Property那么可以忽略get_Name,set_Name。
    • 如果你了解Object那么可以忽略ToString,Equals,GetHasCode,GetType。(所有的引用類型都繼承Object)
    • 如果你知道默認構(gòu)造函數(shù)那么可以忽略.ctor。
    • 現(xiàn)在剩下的OnSay,Age,Name,Say,SayHello5個類是我們定義的,還有2個_name,Haha沒有在上面運行結(jié)果中顯示,我們發(fā)現(xiàn)這個成員有個共同點是:他們都是私有成員。

    如何獲取私有成員
    我們將代碼稍作改動看看效果:

    var memberInfos = helloType.GetMembers(); //上面這行做如下改動 var memberInfos = helloType.GetMembers(BindingFlags.NonPublic //獲取private成員|BindingFlags.Static //獲取static成員|BindingFlags.Instance //獲取實例成員|BindingFlags.Public //獲取public成員); //得到如下結(jié)果: 成員類型:Method 類型名稱:add_OnSay 成員類型:Method 類型名稱:remove_OnSay 成員類型:Method 類型名稱:get_Name 成員類型:Method 類型名稱:set_Name 成員類型:Method 類型名稱:SayHello 成員類型:Method 類型名稱:Say 成員類型:Method 類型名稱:HaHa 成員類型:Method 類型名稱:ToString 成員類型:Method 類型名稱:Equals 成員類型:Method 類型名稱:GetHashCode 成員類型:Method 類型名稱:GetType 成員類型:Method 類型名稱:Finalize 成員類型:Method 類型名稱:MemberwiseClone 成員類型:Constructor 類型名稱:.ctor 成員類型:Property 類型名稱:Name 成員類型:Event 類型名稱:OnSay 成員類型:Field 類型名稱:OnSay 成員類型:Field 類型名稱:_name 成員類型:Field 類型名稱:Age 類型ReflectionAssembly.Hello共19個成員 這里我們之關心我們定義SayHello,Say,HaHa,Name,OnSay,_name,Age的7個成員是否被列出來。

    GetMembers,FindMembers內(nèi)部實現(xiàn)

    Type類型同時也提供FindMembers方法來獲取成員類型,如果觀察其內(nèi)部實現(xiàn)會發(fā)現(xiàn)它們僅僅是一個包裝方法, 它們通過包裝GetMethods,GetFields,GetProperties,GetEvents,GetConstructors方法的實現(xiàn)來獲取所有的成員信息。

    以下方法均提供了多個重載方法

    發(fā)現(xiàn)字段(FildInfo)

    helloType.GetFields();

    發(fā)現(xiàn)屬性(PropertyInfo)

    helloType.GetProperties();

    發(fā)現(xiàn)方法(MethodInfo)

    helloType.GetMethods();

    發(fā)現(xiàn)構(gòu)造器(ConstructorInfo)

    helloType.GetConstructors();

    發(fā)現(xiàn)事件(EventInfo)

    helloType.GetEvents();

    5. 執(zhí)行對類的操作

    調(diào)用字段

    字段類型通過GetValue,SetValue方法對來操作

    //實例化Hello var hello = Activator.CreateInstance(helloType); //調(diào)用private字段 var _name = helloType.GetField("_name",BindingFlags.NonPublic|BindingFlags.Instance); _name.SetValue(hello, "guodf"); Console.WriteLine(_name.GetValue(hello)); //調(diào)用public字段 var age = helloType.GetField("Age"); age.SetValue(hello, "16"); Console.WriteLine(age.GetValue(hello));

    調(diào)用屬性

    屬性類型通過get_**,set_**方法來操作

    //實例化Hello var hello = Activator.CreateInstance(helloType); //調(diào)用屬性 var name = helloType.GetProperty("Name"); name.SetValue(hello, "guodf test"); Console.WriteLine($"_name:{_name.GetValue(hello)}\tName:{name.GetValue(hello)}");

    調(diào)用方法

    方法通過Invoke執(zhí)行方法

    //調(diào)用實例方法 var say = helloType.GetMethod("Say"); say.Invoke(hello,null); //調(diào)用private實例方法 var haha = helloType.GetMethod("HaHa", BindingFlags.Instance | BindingFlags.NonPublic); haha.Invoke(hello, null);

    調(diào)用事件

    //調(diào)用事件 var testEvent = helloType.GetMethod("TestEvent"); var onSay = helloType.GetEvent("OnSay"); Action event1 = () => { Console.WriteLine("event1"); }; Action event2 = () => { Console.WriteLine("event2"); }; //綁定2個方法 onSay.AddEventHandler(hello, event1); onSay.AddEventHandler(hello, event2); testEvent.Invoke(hello,null); //移除一個方法 onSay.RemoveEventHandler(hello, event1); testEvent.Invoke(hello,null);

    調(diào)用靜態(tài)方法

    var sayHello=hello.GetMethod("SayHello"); sayHello.Invoke(null, null);

    隱式反射和顯式反射

    C#中有隱式轉(zhuǎn)換和顯式轉(zhuǎn)換得概念,通常派生類轉(zhuǎn)換為基類型被稱為隱私轉(zhuǎn)換,因為可以直接將派生類型賦值給基類型;反之稱為顯示轉(zhuǎn)換。

    那么在反射得使用過程中,我通常使用兩種實現(xiàn)方式來使用反射對象:一種基于接口的編程方式,另一種則是完全的字符串查找方式。所以我將基于接口的方式稱為顯式反射,這種做法的好處是編程期間我們可以直接使用類型的方法;而另一種基于字符串找好的方式我稱它為隱式反射,因為在使用過程中無論得到那種成員類型都是通過字符串查找實現(xiàn)的。

    反射的優(yōu)缺點

    優(yōu)點

    1. 動態(tài)加載,按需加載 2. 解耦

    缺點

    1. 無編譯期類型安全檢查 2. 性能低

    小結(jié)

    反射一種技術,這種技術可以幫助我們實現(xiàn)一些看起來很酷的編程設計,但這種技術并不完美,它犧牲了效率換來了靈活性。至于這種犧牲的價值當然是仁者見仁智者見智。

    轉(zhuǎn)載于:https://www.cnblogs.com/guodf/p/6585566.html

    總結(jié)

    以上是生活随笔為你收集整理的什么是反射的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。