C#之反射
反射是給你一個程序集dll,可以反射出其中的所有元數據metadata,包括字段、屬性、方法等,反射最重要的重要就是利用反射創建對象,從而達到層與層之間的低耦合效果。IOC依賴註入容器就是反射典型的應用場景,包過MVC、ORM都用到了反射。反射在我們程序設計中是無處不在的,只不過現在有很多第三方的框架、組件幫我們封裝好了,有時候感覺不到反射的應用,下面我們就深入了解一下反射。
1.反射創建對象
1//常規創建對象的方法
IDBHelper iDBHelper = new MySqlHelper(); 2 iDBHelper.Query(); 3 //這種代碼我們應該經常寫 使用接口仍然避免不了對MySqlHelper所在類的dll的依賴
Assembly assembly = Assembly.Load("MySql");//1.加載程序集 註意:一定要在主項目中添加該類庫的引用 該dll要和exe文件在同一個文件夾中 Type type = assembly.GetType("MySql.MySqlHelper");//2.獲取程序集中指定的對象類型 IDBHelper iDBHelper = (IDBHelper)Activator.CreateInstance(type);//3.創建對象 iDBHelper.Query();//反射獲取該類型中的所有公共方法 foreach (var t in type.GetMethods()) { Console.WriteLine(t.Name); } //反射獲取該類型中的所有公共屬性 foreach (var t in type.GetProperties()) { Console.WriteLine(t.Name); }
2.上面只是說明了反射可以創建無參構造函數,反射還可以創建帶參數的構造函數。
public class MySqlHelper : IDBHelper { public string Name { get; set; } protected int Age { get; set; } public MySqlHelper() { Console.WriteLine("{0}被構造-無參",this.GetType().Name); } public MySqlHelper(string Name) { this.Name = Name; Console.WriteLine("帶有一個參數構造被構建"); } public MySqlHelper(string Name, int Age) { this.Name = Name; this.Age = Age; Console.WriteLine("帶有兩個參數構造函數別構建"); } public void Query() { Console.WriteLine("{0}.Query",this.GetType().Name); } protected void Fun() { } }
#region 反射創建對象-有參構造函數
{
Assembly assembly = Assembly.Load("MySql");
Type type = assembly.GetType("MySql.MySqlHelper");
//遍歷所有公共構造函數
foreach (var t in type.GetConstructors())
{
Console.WriteLine("構造函數名:"+t.Name);
foreach (var p in t.GetParameters())
{
Console.WriteLine(p.ParameterType);
}
}
IDBHelper dBHelper = (IDBHelper)Activator.CreateInstance(type);
IDBHelper dBHelper2 = (IDBHelper)Activator.CreateInstance(type,new object[] { "張三"});
IDBHelper dBHelper3 = (IDBHelper)Activator.CreateInstance(type,new object[] { "李四",18});
}
#endregion
運行結果:
4.我們都知道當我們在程序設計的時候運用到了單例模式,該對象只可能被實例化一次。。但是。。。運用反射可以 破壞單例模式 。 即反射可以調用私有構造函數從而創建對象。
public class SqlServerHelper:IDBHelper { //public SqlServerHelper() //{ // Console.WriteLine("{0}被構造",this.GetType().Name); // } private SqlServerHelper() { Console.WriteLine("無參構造函數被創建"); } public void Query() { Console.WriteLine("{0}被構造",this.GetType().Name); } }
public class SqlServerHelper:IDBHelper { //public SqlServerHelper() //{ // Console.WriteLine("{0}被構造",this.GetType().Name); // } private SqlServerHelper() { Console.WriteLine("無參構造函數被創建"); } public void Query() { Console.WriteLine("{0}被構造",this.GetType().Name); } } #region 反射破壞單例 調用私有構造函數創建對象 { Console.WriteLine("反射調用私有構造函數創建對象"); Assembly assembly = Assembly.Load("SqlServer"); Type type = assembly.GetType("SqlServer.SqlServerHelper"); IDBHelper dBHelper = (IDBHelper)Activator.CreateInstance(type,true);//可以調用私有構造函數 dBHelper.Query(); } #endregion
程序結果:
5.反射創建泛型對象
public class GenericClass<T,S> { public GenericClass() { Console.WriteLine("泛型對象被創建"+typeof(T)+typeof(S)); } }
#region 反射創建泛型對象 { Console.WriteLine("反射創建泛型對象"); Assembly assembly = Assembly.Load("MySql"); //Type type = assembly.GetType("MySql.GenericClass"); Type type = assembly.GetType("MySql.GenericClass`2");//泛型類獲取對象 Type genericType = type.MakeGenericType(new Type[] { typeof(int),typeof(string)}); object genericObject = Activator.CreateInstance(genericType); } #endregion
程序結果:
反射除了創建創建對象 還可以調用方法,獲取字段、屬性功能
C#之反射