#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
通過反射創建一個對象的方法:
/// <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; //要強制轉換一下,因為牽涉到編譯性語言和運行時語言 } }
調用的時候直接如下:
var mysqlServerHelper = SimpleFactory.CreateInstance<MySqlServerHelper>(); mysqlServerHelper.Query();
三:反射調用多構造函數,調用私有構造函數(破壞單例),調用泛型類
首先創建一個實體類,包含有參無參構造函數,然后有參無參的方法,如下:
/// <summary> /// sqlServer /// </summary> public class SqlServerHelper : IDBHelper { //private SqlServerHelper() //{ // Console.WriteLine("私有構造函數"); //} public SqlServerHelper() { Console.WriteLine("公有無參構造函數"); } public SqlServerHelper(int iParam) { Console.WriteLine($"int的構造函數--{iParam}"); } 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"); } public void Show1() { Console.WriteLine("Show1的無參構造函數"); } public void Show1(int iParam) { Console.WriteLine($"Show1的int重載--{iParam}"); } public void Show1(int iParam, string sParam) { Console.WriteLine($"Show1兩參數 iparam={iParam};sParam={sParam}"); } public static void Show5(string name) { Console.WriteLine($"靜態方法---{name}"); } }
1:調用有參無參的public構造函數:
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:調用private構造函數:
//私有構造函數 Type singletonType = assembly.GetType("MyReflection.Singleton"); //傳入完整名稱獲取類型(命名空間+類名) var object1 = Activator.CreateInstance(singletonType, true); //設置成true能調用私有/公布的構造函數,如果不設置則只能調用公有構造函數
3:普通方法,靜態方法,重載方法的調用:
//普通方法 MethodInfo methodInfo = dbHelperType.GetMethod("Show"); //調用單個普通的實例方法 methodInfo.Invoke(obSqlServerHelper, null); //第一個參數:是應用對象,第二個參數:是方法需要的參數,如果沒有則設置為null //靜態方法調用 MethodInfo staticMethodInfo = dbHelperType.GetMethod("Show5"); //調用單個普通的實例方法 staticMethodInfo.Invoke(null, new object[] { "靜態方法第一種調用方式" }); //第一個參數:是應用對象,如果是靜態可以不用寫;第二個參數:是方法需要的參數,如果沒有則設置為null staticMethodInfo.Invoke(obSqlServerHelper, new object[] { "靜態方法第二種調用方式" });//重載方法調用 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:調用泛型,首先要創建一個實體類如下:
#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
然后調用泛型方法如下:
//創建泛型 Assembly assembly = Assembly.Load("MyReflection"); //獲取當前路徑下面的dl或者exe,不帶后綴 Type genericType = assembly.GetType("MyReflection.GenericClass`3"); //`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:調用普通方法的泛型方法
1 //類的泛型方法調用 2 Type genericMethodType = assembly.GetType("MyReflection.GenericMethod"); 3 var objectGeneric = Activator.CreateInstance(genericMethodType); 4 MethodInfo genericMethod = genericMethodType.GetMethod("Show"); 5 MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int)); 6 //一定要用genericMethodNew進行調用 7 genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });
四:反射的用途:
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.Type 類--通過這個類可以訪問任何給定數據類型的信息。
System.Reflection.Assembly類--它可以用於訪問給定程序集的信息,或者把這個程序集加載到程序中。
Name 數據類型名
FullName 數據類型的完全限定名(包括命名空間名)
Namespace 定義數據類型的命名空間名
IsAbstract 指示該類型是否是抽象類型
IsArray 指示該類型是否是數組
IsClass 指示該類型是否是類
IsEnum 指示該類型是否是枚舉
IsInterface 指示該類型是否是接口
IsPublic 指示該類型是否是公有的
IsSealed 指示該類型是否是密封類
IsValueType 指示該類型是否是值類型
Console.WriteLine("*********************字段和屬性***********************"); People people = new People() { ID = 111, Name = "名字", Description = "描述" }; Type typePeople = typeof(People); object oPeople = Activator.CreateInstance(typePeople); //new 一個新的對象 //得到所有的字段public聲明,但是么有set和get方法 foreach (var item in typePeople.GetFields()) { Console.WriteLine($"Name1={item.Name};value1={item.GetValue(people)}"); } //得到所有的屬性(有set和get的屬性) foreach (var item in typePeople.GetProperties()) { if (item.Name.Equals("Id")) { item.SetValue(oPeople, 888); } else if (item.Name.Equals("Name")) { item.SetValue(oPeople, "人民"); } Console.WriteLine($"Name={item.Name};value={item.GetValue(oPeople)}"); }
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()方法。
public class MySqlServerHelper { public MySqlServerHelper() { } public void Query() { } }
public class Monitor { public static void Show() { Console.WriteLine("*******************Monitor*********"); long commonTime = 0; long reflectionTime = 0; { //時間測量工具 Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 1000000; i++) { MySqlServerHelper dbHelper = new MySqlServerHelper(); dbHelper.Query(); } watch.Stop(); commonTime = watch.ElapsedMilliseconds; //毫秒 } { Stopwatch watch = new Stopwatch(); watch.Start(); //1:動態加載 Assembly assembly = Assembly.Load("MyReflection"); //2:獲取類型 Type type = assembly.GetType("MyReflection.MySqlServerHelper"); for (int i = 0; i < 1000000; i++) { MySqlServerHelper oDbHelper =(MySqlServerHelper)Activator.CreateInstance(type); oDbHelper.Query(); } watch.Stop(); reflectionTime = watch.ElapsedMilliseconds; } Console.WriteLine($"reflectionTime={reflectionTime};commonTime={commonTime}"); } }
然后調用后發現: 100萬次相差30倍左右,所以反射的是很耗性能,但是如果分布到每次則相差幾毫秒,所以這個性能影響可以忽略掉!