1. 程式人生 > 其它 >.net 反射簡單介紹

.net 反射簡單介紹

1.什麼是反射

反射是.NET中的重要機制,通過反射,可以在執行時獲得程式或程式集中每一個型別(包括類、結構、委託、介面和列舉等)的成員和成員的資訊。有了反射,即可對每一個型別瞭如指掌。另外我還可以直接建立物件,即使這個物件的型別在編譯時還不知道。

2.反射簡單例子

平時我們寫呼叫dll都是新增引用,然後new物件,如

通過反射,我們可以實現同樣的效果,而不需要新增引用,

2.1我們先載入需要反射的dll  (3種方式,第一種最常用(通常我們把需要反射的dll丟在當前路徑下面))

  Assembly assembly = Assembly.Load("Ruanmou.DB.Sqlserver");//1 動態載入     預設載入當前路徑的dll檔案,不需要字尾
   //Assembly assembly1 = Assembly.LoadFile(@"E:\online7\20160928Advanced7Course2Reflection\MyReflection\MyReflection\bin\Debug\Ruanmou.DB.Sqlserver.dll");// 必須是完整路徑
                //Assembly assembly2 = Assembly.LoadFrom("Ruanmou.DB.Sqlserver.dll");// 可以是當前路徑  也可以是完整路徑

 2.2 獲取型別

比如我們引用的這個dll下面有4個類

 我們反射則需要這樣獲取

  foreach (var item in assembly.GetTypes())
                {undefined
                    Console.WriteLine(item.FullName);
                }

下面是打印出來的資訊

  

注:第二行的後面有個佔位符,還有一個1字,這代表這是一個泛型類,有1個引數

2.3 獲取方法名

 foreach (var item in typeDBHelper.GetMethods())
                {undefined
                    Console.WriteLine(item.Name);
                }

下面是打印出來的資訊和類的資訊

2.4 獲取屬性

  foreach (var item in typeDBHelper.GetProperties())
                {undefined
                    Console.WriteLine(item.Name);
                }

 2.5 獲取欄位

    foreach (var item in typeDBHelper.GetFields())
                {undefined
                    Console.WriteLine(item.Name);
                }

2.6 建立物件

 Assembly assembly = Assembly.Load("Ruanmou.DB.Sqlserver");//1 動態載入

 Type typeDBHelper = assembly.GetType("Ruanmou.DB.Sqlserver.DBHelper");//2 獲取型別資訊

 object oDBHelper = Activator.CreateInstance(typeDBHelper);//3 建立物件

2.7 ioc

 簡單來說 簡單工廠+配置檔案+反射=ioc

2.8 反射黑科技(破壞單例,就是呼叫私有的建構函式)

 object oDBHelper = Activator.CreateInstance(typeDBHelper,true);//後面多了個引數

2.9 建立泛型

 Type typeGeneric = assembly.GetType("Ruanmou.DB.Sqlserver.GenericClass`1"); //後面加上佔位符和幾個引數
                    typeGeneric = typeGeneric.MakeGenericType(typeof(int)); //必須指定型別,然後才能建立物件
                    Activator.CreateInstance(typeGeneric);

2.10 方法的呼叫

1. void 

  Type typeTest = assembly.GetType("Ruanmou.DB.Sqlserver.ReflectionTest");//2 獲取型別 (獲取型別資訊的方式不止一個)
  object oTest = Activator.CreateInstance(typeTest);

  MethodInfo method = typeTest.GetMethod("Show1"); //show1是方法名稱
   method.Invoke(oTest, null); //第一個引數是例項物件

2.帶引數的

  MethodInfo method = typeTest.GetMethod("Show2");
  method.Invoke(oTest, new object[] { 11 });

3.靜態方法

   MethodInfo method = typeTest.GetMethod("ShowStatic");
   method.Invoke(null, new object[] { "KOBE→Bryant" });//靜態方法第一個引數填null就可以了

4.過載方法

 GetMethod只能找到一個,要找到過載的,需要指定資訊

  {undefined
                        MethodInfo method = typeTest.GetMethod("Show3", new Type[] { });//代表這是無參
                        method.Invoke(oTest, null);
                    }
                    {undefined
                        MethodInfo method = typeTest.GetMethod("Show3", new Type[] { typeof(int) }); //代表引數是一個int型別的
                        method.Invoke(oTest, new object[] { 11 });
                    }
                    {undefined
                        MethodInfo method = typeTest.GetMethod("Show3", new Type[] { typeof(string) });
                        method.Invoke(oTest, new object[] { "限量版(397-限量版)" });
                    }
                    {undefined
                        MethodInfo method = typeTest.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });//代表有2個引數
                        method.Invoke(oTest, new object[] { "書呆熊@拜仁", 22 });
                    }

2.11 反射欄位和屬性,分別獲取值和設定值

 

                  Type typeTest = assembly.GetType("Ruanmou.DB.Sqlserver.ReflectionTest");
                    object oTest = Activator.CreateInstance(typeTest);
                    //foreach (var item in typeTest.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
                    //{undefined
                    //    Console.WriteLine(item.Name);
                    //}
                    foreach (var prop in typeTest.GetProperties())
                    {undefined
                        Console.WriteLine(prop.GetValue(oTest));
                        Console.WriteLine(prop.Name);
                        if (prop.Name.Equals("Id"))
                        {undefined
                            prop.SetValue(oTest, 22);
                        }
                        else if (prop.Name.Equals("Name"))
                        {undefined
                            prop.SetValue(oTest, "Bond(331-object)");
                        }

                        Console.WriteLine(prop.GetValue(oTest));
                    }

 

附上反射的一些資料

反射的用途:
    (1)使用Assembly定義和載入程式集,載入在程式集清單中列出模組,以及從此程式集中查詢型別並建立該型別的例項。 
    (2)使用Module瞭解包含模組的程式集以及模組中的類等,還可以獲取在模組上定義的所有全域性方法或其他特定的非全域性方法。 
    (3)使用ConstructorInfo瞭解建構函式的名稱、引數、訪問修飾符(如pulic 或private)和實現詳細資訊(如abstract或virtual)等。 
    (4)使用MethodInfo瞭解方法的名稱、返回型別、引數、訪問修飾符(如pulic 或private)和實現詳細資訊(如abstract或virtual)等。
    (5)使用FiedInfo瞭解欄位的名稱、訪問修飾符(如public或private)和實現詳細資訊(如static)等,並獲取或設定欄位值。
    (6)使用EventInfo瞭解事件的名稱、事件處理程式資料型別、自定義屬性、宣告型別和反射型別等,新增或移除事件處理程式。 
    (7)使用PropertyInfo瞭解屬性的名稱、資料型別、宣告型別、反射型別和只讀或可寫狀態等,獲取或設定屬性值。 
    (8)使用ParameterInfo瞭解引數的名稱、資料型別、是輸入引數還是輸出引數,以及引數在方法簽名中的位置等。

反射用到的名稱空間:
    System.Reflection
    System.Type
    System.Reflection.Assembly
    
反射用到的主要類:
    System.Type 類--通過這個類可以訪問任何給定資料型別的資訊。
    System.Reflection.Assembly類--它可以用於訪問給定程式集的資訊,或者把這個程式集載入到程式中。
    
System.Type類:
    System.Type 類對於反射起著核心的作用。但它是一個抽象的基類,Type有與每種資料型別對應的派生類,我們使用這個派生類的物件的方法、欄位、屬性來查詢有關該型別的所有資訊。
    獲取給定型別的Type引用有3種常用方式:
    ●使用 C# typeof 運算子。
        Type t = typeof(string);
    ●使用物件GetType()方法。
        string s = "grayworm";
        Type t = s.GetType(); 
    ●還可以呼叫Type類的靜態方法GetType()。
        Type t = Type.GetType("System.String");
       
    上面這三類程式碼都是獲取string型別的Type,在取出string型別的Type引用t後,我們就可以通過t來探測string型別的結構了。 
            string n = "grayworm";
            Type t = n.GetType();
            foreach (MemberInfo mi in t.GetMembers())
            {
                Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name);
            }
    
    Type類的屬性:
        Name 資料型別名
        FullName 資料型別的完全限定名(包括名稱空間名)
        Namespace 定義資料型別的名稱空間名
        IsAbstract 指示該型別是否是抽象型別
        IsArray   指示該型別是否是陣列
        IsClass   指示該型別是否是類
        IsEnum   指示該型別是否是列舉
        IsInterface    指示該型別是否是介面
        IsPublic 指示該型別是否是公有的
        IsSealed 指示該型別是否是密封類
        IsValueType 指示該型別是否是值型別
    Type類的方法:
        GetConstructor(), GetConstructors():返回ConstructorInfo型別,用於取得該類的建構函式的資訊
        GetEvent(), GetEvents():返回EventInfo型別,用於取得該類的事件的資訊
        GetField(), GetFields():返回FieldInfo型別,用於取得該類的欄位(成員變數)的資訊
        GetInterface(), GetInterfaces():返回InterfaceInfo型別,用於取得該類實現的介面的資訊
        GetMember(), GetMembers():返回MemberInfo型別,用於取得該類的所有成員的資訊
        GetMethod(), GetMethods():返回MethodInfo型別,用於取得該類的方法的資訊
        GetProperty(), GetProperties():返回PropertyInfo型別,用於取得該類的屬性的資訊
    可以呼叫這些成員,其方式是呼叫Type的InvokeMember()方法,或者呼叫MethodInfo, PropertyInfo和其他類的Invoke()方法。 
    
    檢視類中的構造方法:
        NewClassw nc = new NewClassw();
        Type t = nc.GetType();
        ConstructorInfo[] ci = t.GetConstructors();    //獲取類的所有建構函式
        foreach (ConstructorInfo c in ci) //遍歷每一個建構函式
        {
            ParameterInfo[] ps = c.GetParameters();    //取出每個建構函式的所有引數
            foreach (ParameterInfo pi in ps)   //遍歷並列印所該建構函式的所有引數
            {
                Console.Write(pi.ParameterType.ToString()+" "+pi.Name+",");
            }
            Console.WriteLine();
        }
    
    用建構函式動態生成物件:
        Type t = typeof(NewClassw);
        Type[] pt = new Type[2];
        pt[0] = typeof(string);
        pt[1] = typeof(string);
        //根據引數型別獲取建構函式 
        ConstructorInfo ci = t.GetConstructor(pt); 
        //構造Object陣列,作為建構函式的輸入引數 
        object[] obj = new object[2]{"grayworm","hi.baidu.com/grayworm"};   
        //呼叫建構函式生成物件 
        object o = ci.Invoke(obj);    
        //呼叫生成的物件的方法測試是否物件生成成功 
        //((NewClassw)o).show();    
    
    用Activator生成物件:
        Type t = typeof(NewClassw);
        //建構函式的引數 
        object[] obj = new object[2] { "grayworm", "hi.baidu.com/grayworm" };   
        //用Activator的CreateInstance靜態方法,生成新物件 
        object o = Activator.CreateInstance(t,"grayworm","hi.baidu.com/grayworm"); 
        //((NewClassw)o).show();

    檢視類中的屬性:
        NewClassw nc = new NewClassw();
        Type t = nc.GetType();
        PropertyInfo[] pis = t.GetProperties();
        foreach(PropertyInfo pi in pis)
        {
            Console.WriteLine(pi.Name);
        }
    
    檢視類中的public方法:
        NewClassw nc = new NewClassw();
        Type t = nc.GetType();
        MethodInfo[] mis = t.GetMethods();
        foreach (MethodInfo mi in mis)
        {
            Console.WriteLine(mi.ReturnType+" "+mi.Name);
        }
    
    檢視類中的public欄位
        NewClassw nc = new NewClassw();
        Type t = nc.GetType();
        FieldInfo[] fis = t.GetFields();
        foreach (FieldInfo fi in fis)
        {
            Console.WriteLine(fi.Name);
        } (http://hi.baidu.com/grayworm)
       
    用反射生成物件,並呼叫屬性、方法和欄位進行操作 
        NewClassw nc = new NewClassw();
        Type t = nc.GetType();
        object obj = Activator.CreateInstance(t);
        //取得ID欄位 
        FieldInfo fi = t.GetField("ID");
        //給ID欄位賦值 
        fi.SetValue(obj, "k001");
        //取得MyName屬性 
        PropertyInfo pi1 = t.GetProperty("MyName");
        //給MyName屬性賦值 
        pi1.SetValue(obj, "grayworm", null);
        PropertyInfo pi2 = t.GetProperty("MyInfo");
        pi2.SetValue(obj, "hi.baidu.com/grayworm", null);
        //取得show方法 
        MethodInfo mi = t.GetMethod("show");
        //呼叫show方法 
        mi.Invoke(obj, null);
        
System.Reflection.Assembly類 
     Assembly類可以獲得程式集的資訊,也可以動態的載入程式集,以及在程式集中查詢型別資訊,並建立該型別的例項。
    使用Assembly類可以降低程式集之間的耦合,有利於軟體結構的合理化。
    
    通過程式集名稱返回Assembly物件
        Assembly ass = Assembly.Load("ClassLibrary831");
    通過DLL檔名稱返回Assembly物件
        Assembly ass = Assembly.LoadFrom("ClassLibrary831.dll");
    通過Assembly獲取程式集中類 
        Type t = ass.GetType("ClassLibrary831.NewClass");   //引數必須是類的全名
    通過Assembly獲取程式集中所有的類
        Type[] t = ass.GetTypes();
       
    //通過程式集的名稱反射
    Assembly ass = Assembly.Load("ClassLibrary831");
    Type t = ass.GetType("ClassLibrary831.NewClass");
    object o = Activator.CreateInstance(t, "grayworm", "http://hi.baidu.com/grayworm");
    MethodInfo mi = t.GetMethod("show");
    mi.Invoke(o, null);

   //通過DLL檔案全名反射其中的所有型別
    Assembly assembly = Assembly.LoadFrom("xxx.dll的路徑");
    Type[] aa = a.GetTypes();

    foreach(Type t in aa)
    {
        if(t.FullName == "a.b.c")
        {
            object o = Activator.CreateInstance(t);
        }
    }

 

 

https://blog.csdn.net/wu1020300665/article/details/82958455