.NET 反射原理及其运用
一.何謂反射
反射:是.net framework提供的一個訪問metadata的幫助類庫,可以獲取信息并且使用
動態是反射中的最大優點。
二:反射如何使用
#region 反射的加載方式 獲取當前路徑下面的dl或者exe,不帶后綴(MyReflection.exe 是編譯后生成的exe執行文件),從Exe所在的路徑進行查找 Assembly assembly = Assembly.Load(@"MyReflection"); //獲取完整路徑下面的dl或者exe,要加后綴 Assembly assemblyFrom = Assembly.LoadFrom(@"D:\MyReflection\bin\Debug\MyReflection.exe"); //獲取完整路徑下面的dl或者exe,要加后綴 Assembly assemblyFile = Assembly.LoadFile(@"D:\MyReflection\bin\Debug\MyReflection.exe"); foreach (var item in assembly.GetModules()) {//Modules當前的exe或者dll的名字(MyReflection.exe)Console.WriteLine(item.Name); } //當前所包含的實體類(IDBHelper,SqlServerHelper,Program) foreach (var item in assembly.GetTypes()) {foreach(var method in item.GetMethods()){Console.WriteLine(method.Name); }Console.WriteLine(item.Name); }foreach (var item in assembly.GetCustomAttributes()) {Console.WriteLine(item.ToString()); } //獲取到有多個構造函數 foreach (var ctor in type.GetConstructors()) { Console.WriteLine(ctor.GetParameters()); //獲取構造函數里面的參數 foreach (var item in ctor.GetParameters()) { Console.WriteLine(item.ParameterType); } } #endregion三.反射的應用
(一)可以利用反射 創建一個類的實例,并調用他的方法
1.創建步驟
例如:
(1).獲取類型:
Type dbhelperType = assembly.GetTyp(“Ruanmou.DB.MySql.MySqlHelper”);//== 獲取所需創建類型的類型信息,傳參數必須傳遞完整類名,從命名空間開始==
(2).創建類型對應的實例對象
//用Activator.CreateInstance(類型參數)創建所需類型的實例對象
object oDBHelper = Activator.CreateInstance(dbhelperType);
(3).轉換并調用方法:
用其對應的接口進行轉換
IDBHelper idbhelper = oDBHelper as IDBHelper;
idbhelper.Query();
2.具體應用
在寫程序的時候,需要靈活運用類的時候,可以先在配置文件中,將需要的類型配置進去,然后在程序中根據配置文件靈活的創建所需要的類型對象:舉例,程序有可能需要多種數據庫,MySql 和SqlServer,寫底層數據庫連接的時候并不知道上層需要哪個,于是可以利用在配置文件中的連接字符串中配置Provider的dll,用反射的方式在底層創建連接字符串的時候,根據上層傳入的連接字符串來靈活創建底層連接Connection.
/// <summary> /// 反射得到一個對象/// </summary>public class SimpleFactory{//讀取配置文件AppSetting里面的key// <appSettings>// <add key = "DbConfig" value="MyReflection,MyReflection.MySqlServerHelper"/>//</appSettings>private static string ConfigStr = ConfigurationManager.AppSettings["DbConfig"];private static string DllName = ConfigStr.Split(',')[0]; //命名空間private static string TypeName = ConfigStr.Split(',')[1]; //類型要完整命名空間+類名public static T CreateInstance<T>(){Assembly assembly = Assembly.Load(DllName);Type type = assembly.GetType(TypeName);var objectInstance = Activator.CreateInstance(type);return (T)objectInstance; //要強制轉換一下,因為牽涉到編譯性語言和運行時語言}}(二):反射調用多構造函數,調用私有構造函數(破壞單例),調用泛型類
首先創建一個實體類,包含有參無參構造函數,然后有參無參的方法,如下:
/// <summary>/// sqlServer/// </summary>public class SqlServerHelper : IDBHelper{//private SqlServerHelper()//{// Console.WriteLine("私有構造函數");//}//無參構造函數public SqlServerHelper(){Console.WriteLine("公有無參構造函數");}//傳入一個int型參數的構造函數public SqlServerHelper(int iParam){Console.WriteLine($"int的構造函數--{iParam}");}//傳入一個string型參數的構造函數public SqlServerHelper(string sParam){Console.WriteLine($"string的構造函數--{sParam}");}//傳入兩個參數的構造函數public SqlServerHelper(int iParam, string sParam){Console.WriteLine($"int和string的構造函數--int={iParam} ;string={sParam}");}//類內部的無參方法public void Show(){Console.WriteLine("Show");}//類內部的Show1的無參方法public void Show1(){Console.WriteLine("Show1的無參方法");}//類內部的Show1的int重載方法public void Show1(int iParam){Console.WriteLine($"Show1的int重載--{iParam}");}//類內部的Show1的兩參重載方法public void Show1(int iParam, string sParam){Console.WriteLine($"Show1兩參數 iparam={iParam};sParam={sParam}");} }1.調用上面例子類中的 有參 或者 無參構造函數
Assembly assembly = Assembly.Load("MyReflection"); //獲取當前路徑下面的dl或者exe,不帶后綴 Type dbHelperType = assembly.GetType("MyReflection.SqlServerHelper"); //傳完整名稱獲類型(命名空間+類名) //調用多個構造函數(有參,無參) var obSqlServerHelper = Activator.CreateInstance(dbHelperType); //無參的構造函數 Activator.CreateInstance(dbHelperType, new object[] { 11 }); //int的構造函數 Activator.CreateInstance(dbHelperType, new object[] { "testbywss" }); //調用string的構造函數 Activator.CreateInstance(dbHelperType, new object[] { 123, "testbywss" }); //調用string的構造函數2. 調用類的私有構造函數
//私有構造函數Type singletonType = assembly.GetType("MyReflection.Singleton"); //傳入完整名稱獲取類型(命名空間+類名)var object1 = Activator.CreateInstance(singletonType, true); //設置成true能調用私有/公布的構造函數,如果不設置則只能調用公有構造函數3.不必強制類型轉換,調用 普通方法,靜態方法,重載方法:
在利用了反射實例化對象之后,可以不需要強制類型轉換,直接調用其方法
Type dbhelperType = assembly.GetTyp(“Ruanmou.DB.SqlServer.SqlServerHelper ”);
object obSqlServerHelper = Activator.CreateInstance(dbhelperType);
(1)普通方法
Type 類型 的對象,有一個方法 GetMethods方法,可以獲取這個類型對象中所指定的方法,
如下:
MethodInfo methodInfo = dbhelperType.GetMethod(“Show”); //MethodInfo 類,用于描述方法
用獲取到指定方法的 MethodInfo 對象 來調用方法
methodInfo.Invoke(obSqlServerHelper, null); //第一個參數:要調用方法的實例,普通方法必須實例化之后進行調用,上面已經用Activator.CreateInstance實例化了一個該Type的實例,這里將其傳入,第二個參數:是方法需要的參數,如果沒有則設置為null
(2) 靜態方法調用
MethodInfo staticMethodInfo = dbHelperType.GetMethod(“Show5”); //調用單個普通的實例方法
== staticMethodInfo.Invoke(null, new object[] { “靜態方法第一種調用方式” }); //第一個參數:是應用對象,如果是靜態可以不用寫;第二個參數:是方法需要的參數,如果沒有則設置為null ==
staticMethodInfo.Invoke(obSqlServerHelper, new object[] { “靜態方法第二種調用方式” });//重載方法調用
(3) 調用重載方法
重載方法
MethodInfo method2 = dbHelperType.GetMethod(“Show1”, new Type[] { }); //調用無參的函數
method2.Invoke(obSqlServerHelper, null);
MethodInfo method3 = dbHelperType.GetMethod(“Show1”, new Type[] { typeof(int) }); //int參數的方法
method3.Invoke(obSqlServerHelper, new object[] { 11 });
MethodInfo method4 = dbHelperType.GetMethod(“Show1”, new Type[] { typeof(int), typeof(string) }); //調用2個參數的方法,new Type[] { typeof(int), typeof(string) } 順序一定要跟調用的方法的參數順序保持一致
method4.Invoke(obSqlServerHelper, new object[] { 1111, “ddd” });
4:調用泛型
(1)首先要創建一個實體類如下:
#region 泛型類public class GenericClass<T, W, F>{public void Show(T t, W w, F f){Console.WriteLine($"t.type={t.GetType().Name};}");}}public class GenericMethod{public void Show<T, W, X>(T t, W w, X x){Console.WriteLine($"t.type={t.GetType().Name};");}}public class GenericDouble<T>{public void Show<W, X>(T t, W w, X x){Console.WriteLine($"t.type={t.GetType().Name};");}}#endregion(2)調用泛型方法如下
//創建泛型
Assembly assembly = Assembly.Load(“MyReflection”); //獲取當前路徑下面的dl或者exe,不帶后綴
== 創建泛型類,創建泛型類的時候,除了寫好類名,還要給占位符,以告訴系統這個類是一個泛型類,3個占位符,表示泛型類傳入三個類型參數。==
Type genericType = assembly.GetType("MyReflection.GenericClass3"); //3是泛型類需要的參數
== 在調用實例化之前,要先指定具體的泛型的類型==
Type typeGenericNew = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); //需要指定泛型類的類型
GenericClass<int, int, int> oGeneric = (GenericClass<int, int, int>)Activator.CreateInstance(typeGenericNew);
oGeneric.Show(1, 30, 60);
Type genericType1 = assembly.GetType(“MyReflection.GenericMethod”); //普通的類
var genericMethod = Activator.CreateInstance(genericType1) as GenericMethod;
genericMethod.Show<int, string, double>(1, “1”, 2);
5:調用私有方法
//私有方法 //調用私有方法,有參數 MethodInfo method5 = dbHelperType.GetMethod("Show5", BindingFlags.NonPublic | BindingFlags.Instance); method5.Invoke(obSqlServerHelper, new object[] { 5.0 });//私有方法,無參數 MethodInfo method6 = dbHelperType.GetMethod("Show6", BindingFlags.NonPublic | BindingFlags.Instance); method6.Invoke(obSqlServerHelper, null);6:調用普通方法的泛型方法
//類的泛型方法調用 Type genericMethodType = assembly.GetType("MyReflection.GenericMethod"); var objectGeneric = Activator.CreateInstance(genericMethodType); MethodInfo genericMethod = genericMethodType.GetMethod("Show"); //這一步是調用泛型方法的關鍵,給泛型方法的參數類型指定具體類型,并告訴系統這是一個泛型方法 MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int));//對泛型方法進行調用,傳入的第一個參數是調用哪個實例的這個泛型方法,第二個參數是傳入參數
genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });
總結
以上是生活随笔為你收集整理的.NET 反射原理及其运用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯云 coding使用
- 下一篇: 关于Raspbian中KODI无法播放视