# C# 反射 (Reflect)
1.基本內容
我們可以使用反射動態地創建類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。然后,可以調用類型的方法或訪問其字段和屬性。
最基本的調用:
Assembly assembly = Assembly.Load("DB.SqlServer");//將加載dll
Type type = assembly.GetType("DB.SqlServer.SqlServerHelper");//得到DLL 中的SqlServerHelper 類
object obj = Activator.CreateInstance(type);//創建類的實例
SqlServerHelper helper = (SqlServerHelper)obj;//將創建的Object 對象轉換為SqlServerHelper對象
helper.Query();//調用對象的方法
2.創建對象
工廠方法
反射的一個應用場景是,當我們開發的程序的數據庫是可能變化時,就會用到反射,入下述代碼:
//這是一個DB接口層
namespace DB.Interface
{public interface IDBHelper{void Query();}
}
//這是SqlServer數據庫的操作層
namespace DB.SqlServer
{public class SqlServerHelper : IDBHelper//繼承自DB接口層{public void Query(){Console.WriteLine("我是{0}", typeof(SqlServerHelper));}}
}
//這是MySql數據庫的操作層
namespace DB.MySql
{public class MySqlHelper : IDBHelper//繼承自DB接口層{public void Query(){Console.WriteLine("我是{0}", typeof(MySqlHelper));}}
}
然后我們會建造一個工廠類,專門用于生產對象:
//這是工廠層
public class Factory
{static string IDBHelperConfig = System.Configuration.ConfigurationManager.AppSettings["IDBHelperConfig"];static string DllName = IDBHelperConfig.Split(',')[0];static string TypeName = IDBHelperConfig.Split(',')[1];public static IDBHelper CreateDBHelper(){Assembly assembly = Assembly.Load(DllName);//將加載dll Type type = assembly.GetType(TypeName);//得到DLL 中的SqlServerHelper 類object obj = Activator.CreateInstance(type);//創建類的實例return (IDBHelper)obj;//將創建的Object 對象轉換為IDBHelper對象 并返回}
}
然后在app.config 文件中添加配置:
<appSettings><!--這是配置字符串--><add key="IDBHelperConfig" value="DB.SqlServer,DB.SqlServer.SqlServerHelper"/>
</appSettings>
最后在調用層面調用:
//這是調用
IDBHelper dbHelper = Factory.CreateDBHelper();
dbHelper.Query();
這樣當數據庫從SqlServer 修改為 MySql 時,我們只需要修改app.config中的配置字符串即可,而不需要修改源代碼,這樣有利于我們程序的維護,與穩定。
帶參數對象創建
基礎類
namespace Model
{public class Person{public int Id { get; set; }public string Name { get; set; }public DateTime CreateDate { get; set; }public Person(int id){Console.WriteLine("我是有1個參數的構造函數!");this.Id = id;}public Person(int id, string name){Console.WriteLine("我是有2個參數的構造函數!");this.Id = id;this.Name = name;}public Person(int id, string name, DateTime createDate){Console.WriteLine("我是有3個參數的構造函數!");this.Id = id;this.Name = name;this.CreateDate = createDate;}private Person(){Console.WriteLine("我是私有的,無參數構造函數");}}
}
有參數的構造函數調用方式:
Assembly assembly = Assembly.Load("Model");
Type personType = assembly.GetType("Model.Person");
//調用帶1個參數的構造函數
object obj = Activator.CreateInstance(personType, new object[] { 123 });
//調用帶2個參數的構造函數
object obj2 = Activator.CreateInstance(personType, new object[] { 123, "Oliver" });
//調用帶3個參數的構造函數
object obj3 = Activator.CreateInstance(personType, new object[] { 123, "Oliver", DateTime.Now });
調用私有構造函數
Assembly assembly = Assembly.Load("Model");
Type personType = assembly.GetType("Model.Person");
//調用私有函數
object obj4 = Activator.CreateInstance(personType,true);
泛型類創建
基礎類
namespace Model
{//添加泛型類public class GenericClass<T>{public GenericClass(){Console.WriteLine("我是泛型類的構造函數!");}public T GetT(){return default(T);}}
}
通過反射的方法創建泛型對象
Assembly assembly = Assembly.Load("Model");
Type gennericClassType = assembly.GetType("Model.GenericClass`1");//如果是一個泛型需要在后面添加`1,否則取出來的時NULL
Type newGennericClassType = gennericClassType.MakeGenericType(new Type[] { typeof(int) });
var obj = Activator.CreateInstance(newGennericClassType);
注意反射泛型類的時候GetType方法傳入的類名稱,需要在后面添加相應的泛型個數。下面這句代碼也相應的說明這個情況。
//輸出的值也會有一個`1
Console.WriteLine(typeof(GenericClass<int>));//輸出:Model.GenericClass`1[System.Int32]
3.調用方法
基礎類
namespace Model
{public class Person{public int Id { get; set; }public string Name { get; set; }public DateTime CreateDate { get; set; }public string Memo;//字段public Person(int id){Console.WriteLine("我是有1個參數的構造函數!");this.Id = id;}public Person(int id, string name){Console.WriteLine("我是有2個參數的構造函數!");this.Id = id;this.Name = name;}public Person(int id, string name, DateTime createDate){Console.WriteLine("我是有3個參數的構造函數!");this.Id = id;this.Name = name;this.CreateDate = createDate;}private Person(){Console.WriteLine("我是私有的,無參數構造函數");}//帶有返回值的無參方法public DateTime Show(){Console.WriteLine("我是帶有返回值的無參方法。");return DateTime.Now;}//帶有參數的方法public void Show2(int i){Console.WriteLine("我是Show2(int i).i=" + i);}//重載方法public void Show3(int i){Console.WriteLine("我是Show3(int i).i=" + i);}//重載方法public void Show3(string s){Console.WriteLine("我是Show3(string s).s=" + s);}//私有方法private void Show4(){Console.WriteLine("我是私有方法");}//靜態方法public static void Show5(){Console.WriteLine("我是靜態方法");}}
}
無參方法
Assembly assembly = Assembly.Load("Model");//加載dll
Type personType = assembly.GetType("Model.Person");//得到類
object objPerson = Activator.CreateInstance(personType, true);//創建對象
//調用 有返回值 無參數的方法
MethodInfo show = personType.GetMethod("Show");//找到方法
DateTime dt = (DateTime)(show.Invoke(objPerson, new object[] { }));//調用,并接收返回值
帶參數方法
//調用 帶有參數的方法
MethodInfo show2 = personType.GetMethod("Show2");
show2.Invoke(objPerson, new object[] { 123 });
重載方法
//調用 重載方法1
MethodInfo show3 = personType.GetMethod("Show3", new Type[] { typeof(int) });
show3.Invoke(objPerson, new object[] { 234 });//調用 重載方法2
MethodInfo show3_1 = personType.GetMethod("Show3", new Type[] { typeof(string) });
show3_1.Invoke(objPerson, new object[] { "ABC" });
私有方法
//調用私有方法
MethodInfo show4 = personType.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic);
show4.Invoke(objPerson, new object[] { });
靜態方法(兩種形式)
//調用靜態方法
MethodInfo show5 = personType.GetMethod("Show5");
show5.Invoke(objPerson, new object[] { });//類似于 實例調用
show5.Invoke(null, new object[] { });//類似于直接通過類名稱調用
調用泛型類的泛型方法
基礎類
namespace Model
{//添加泛型類public class GenericClass<T>{public GenericClass(){Console.WriteLine("我是泛型類的構造函數!");}public T GetT<S>(T t, S s){Console.WriteLine("我是泛型類中的泛型方法!t_type:{0}, t_value:{1}\ts_type:{2}, s_value:{3}", typeof(T), t, typeof(S), s);return t;}}
}
調用GenericClass類的GetT方法
Assembly assembly = Assembly.Load("Model");
Type genericClassType = assembly.GetType("Model.GenericClass`1");//`1 千萬別忘記
Type newGenericClassType = genericClassType.MakeGenericType(new Type[] { typeof(int) });
object obj= Activator.CreateInstance(newGenericClassType);//創建對象
MethodInfo methodInfo = newGenericClassType.GetMethod("GetT");
MethodInfo newMethodInfo = methodInfo.MakeGenericMethod(new Type[] { typeof(string) });
newMethodInfo.Invoke(obj, new object[] { 123, "Oliver" });//輸出:我是泛型類中的泛型方法!t_type:System.Int32, t_value:123 s_type:System.String, s_value:Oliver
4.get set 屬性、字段
屬性操作
Person p = new Person(1, "Oliver", DateTime.Now);
Type t = p.GetType();
PropertyInfo propertyInfo = t.GetProperty("Id");
Console.WriteLine(propertyInfo.GetValue(p));//獲取 屬性的值。輸出 1
propertyInfo.SetValue(p,123);//獲取 屬性的值
Console.WriteLine(propertyInfo.GetValue(p));//設置 屬性的值。輸出 123//遍歷屬性
foreach (var prop in t.GetProperties())
{Console.WriteLine("{0}.{1}={2}", typeof(Person), propertyInfo.Name, prop.GetValue(p));/*輸出:Model.Person.Id=123Model.Person.Id=OliverModel.Person.Id=2018/8/8 22:15:09*/
}
字段操作
Person p = new Person(1, "Oliver", DateTime.Now);
Type t = p.GetType();
FieldInfo fieldInfo = t.GetField("Memo");
Console.WriteLine(fieldInfo.GetValue(p));//獲取 屬性的值。輸出 空字符串
fieldInfo.SetValue(p, "自律給我自由");//獲取 屬性的值
Console.WriteLine(fieldInfo.GetValue(p));//設置 屬性的值。輸出 自律給我自由