雖然還在學校讀書,反射實際寫的不多。但感覺反射在程序開發中用得還是挺多的,對我來說也是.NET中的一個難點。通過反射,我們可以在運行時獲得.NET中的每一個類型的成員,這些類型包括類、結構、委托和枚舉。有了反射,即可對每一個類型了如指掌。只要獲得了構造函數的信息,即可直接創建對象,即使這個對象的類型在編譯時還不知道。
1.一個反射的例子
我們建立一個類庫ClassPeople和一個控制台應用程序CA,下面的代碼是ClassPeople類庫裡的People類和Man類
public class People { private string name = null; public People() { } public People(string strName) { name = strName; } public void Say() { if (name == null) { Console.WriteLine("hi~~"); } Console.WriteLine("hi"+name); } } public class Man { void Eat(){ Console.WriteLine("EAT"); } }
下面的代碼為CA項目裡的Main方法。
static void Main(string[] args) { Type people=null; //注意:執行這句代碼時要將ClassPeople.dll復制到Debug目錄下,這樣才能找到這個文件 Assembly ass = Assembly.LoadFrom("ClassLibrary1.dll"); Type[] mytypes = ass.GetTypes(); Console.WriteLine("列出程序集中的所有類型"); foreach (Type t in mytypes) { Console.WriteLine(t.Name); if (t.Name == "People") { people = t; } } Console.WriteLine("列出People類中的方法:"); MethodInfo[] methodInfo = people.GetMethods(); foreach (MethodInfo mi in methodInfo) { Console.WriteLine(mi.Name); } //實例化People,並調用Say方法 Object obj = Activator.CreateInstance(people); Object objName = Activator.CreateInstance(people, "kobe"); MethodInfo minfo = people.GetMethod("Say"); Console.WriteLine("調用Say方法"); minfo.Invoke(obj, null); minfo.Invoke(objName, null); Console.ReadLine(); }
2.反射常用類與方法
Assembly:通過這個類可以加載操縱一個程序集,並獲取程序集內部信息。
EventInfo:這個類保存給定的事件信息。
FieldInfo:保存給定的字段信息。
MethodInfo:保存給定的方法信息。
ParameterInfo:保存參數信息。
PropertyInfo:保存屬性信息。
Module:這個類可以使你能訪問多個程序集中的給定模塊。
Type類也是用的比較多,我們可以通過Type類得到一個類的內部信息或者反射創建一個對象。一般有三種方式去得到Type對象。
Type type=typeof(類名);
Type type=ExampleClass.GetType();
Type type=Type.GetType("要獲取的類型的程序集限定名稱");
我們還注意到Assembly加載程序集時有3個方法,分別是Load(),LoadFrom(),LoadFile()。這三個方法將目標托管程序集加載到當前應用程序域然後生成對應程序集實例。我們要知道Load是優先使用的,因為LoadFrom其實是將信息傳給Load去實現,LoadFile則不會加載程序集引用的程序集。我在百度查資料時還發現使用LoadFrom可能還會出錯,LoadFrom不能加載標識相同但路徑不同的程序集,當使用LoadFrom時,和Load方法一樣第一次加載程序集的信息無論失敗還是成功都會被緩存,那麼加載目錄A中的程序集C.dll時則會保存記錄,如果加載B目錄下的C.dll時則會直接給出第一次緩存的程序集,也就是目錄A中的C.dll。
3.通過反射實現工廠模式
class Program { static void Main(string[] args) { //使用ReflectFactory工廠去得到想要的類 IPeople xiaoHua = ReflectFactory.CreatePeopleByReflect("XiaoHua"); IPeople xiaoHon = ReflectFactory.CreatePeopleByReflect("XiaoHon"); xiaoHua.Eat(); xiaoHon.Eat(); Console.ReadLine(); } } //通過這個類得到要創建的類 public class ReflectFactory { public static IPeople CreatePeopleByReflect(string typeName) { Type type = Type.GetType("ConsoleApplication1."+typeName); ConstructorInfo ci = type.GetConstructor(System.Type.EmptyTypes); return (IPeople)ci.Invoke(null); } } //定義了XiaoHua和XiaoHon2個類和它們的父接口IPeople public interface IPeople { void Eat(); } public class XiaoHua : IPeople { public void Eat() { Console.WriteLine("小花吃2個梨子"); } } public class XiaoHon : IPeople { public void Eat() { Console.WriteLine("小紅吃3個蘋果"); } } //下面是不用反射的寫法。這樣的話就要為每個類寫一個創造類或創造的方法,比如要得到XiaoHua類我們要再寫一個GetXiaoHua類, //如果又有新成員加入,那豈不是還要再新增類或方法,而采用反射則可以隨便添加,只需要實現IPeople接口即可,這就是我體會到的反射的好處。 public interface FactoryPeople { IPeople GetPeople(); } public class GetXiaoHua : FactoryPeople { public IPeople GetPeople() { return new XiaoHua(); } } public class GetXiaoHon : FactoryPeople { public IPeople GetPeople() { return new XiaoHon(); } }