反射Demo:html
public class Person { public int Age; public void SayHello() { Console.WriteLine("Hello Person"); } }
class Program { static void Main(string[] args) { //把程序集像讀取文件同樣讀取出來,動態的調用程序集裏面的方法 Person p = new Person(); /* * 使用Type描述類型特徵 Type t1=typeof(ClassName); Type t2=ClassName.GetType(); t1.GetEvents/t1.GetFields/ t1.GetMembers t1.GetMethods() //返回全部公共方法 */ Type t1 = typeof(Person); Type t2 = p.GetType(); //GetEvents 獲取全部的事件 EventInfo[] events = t1.GetEvents(); foreach (var item in events) { Console.WriteLine("Event: " + item.Name); } //GetFields 獲取全部的public字段 FieldInfo[] fields = t1.GetFields(); foreach (var item in fields) { Console.WriteLine("Fields: " + item.Name); } //GetMethods 獲取全部的方法 MethodInfo[] methods = t1.GetMethods(); foreach (var item in methods) { Console.WriteLine("Method: " + item.Name); } Console.ReadKey(); } }
反射:【從文件中讀取程序集中的成員,並使用它】函數
->實現步驟:spa
->使用Assembly.LoadFrom(文件名全名) 【得到程序集對象Assembly】設計
->使用GetTypes()得到全部的類型信息(Type對象) 【讀取類型 GetType】code
->Activator.CreateInstance(Type類型的數據)建立指定類型的對象 【建立對象 Activator.CreateInstance】//實例.方法()htm
->若是須要調用方法,使用<type>.GetMethod(方法名)得到MethodInfo類型對象 【得到方法 <type>.GetMethod】對象
->調用 方法對象.Innvoke(實例,參數);blog
//DrHao 類庫事件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DrHao { public class Hao { public void Fun1() { Console.WriteLine("我是沒有參數的Fun1"); } public void Fun1(int num1) { Console.WriteLine("參數是:" + num1); } public int Fun1(int num1, int num2) { return num1 + num2; } private void Func() { Console.WriteLine("無參數的私有方法"); } } }
//Main函數get
class Program { static void Main(string[] args) { //把程序集像讀取文件同樣讀取出來,動態的調用程序集裏面的方法 //反射 //讀取程序集 Assembly asm = Assembly.LoadFrom(@"E:\Program2013\20160416_Reflect\DrHao\bin\Debug\DrHao.dll"); //讀取類型 Type t = asm.GetType("DrHao.Hao"); //建立對象信息 object o = Activator.CreateInstance(t); //得到方法 ////私有方法 //MethodInfo method = t.GetMethod("Func", BindingFlags.Instance|BindingFlags.NonPublic); MethodInfo method = t.GetMethod("Fun1", new Type[] { typeof(int), typeof(int) }); object result = method.Invoke(o, new object[] { 123, 456 }); Console.WriteLine("|{0}|", result); Console.ReadKey(); } }
關於.NET中的反射,經常使用的有三個方法:
Assembly.Load()
Assembly.LoadFrom()
Assembly.LoadFile()
1. Assembly.Load()
Load()方法接收一個String或AssemblyName類型做爲參數,這個參數其實是須要加載的程序集的強名稱(名稱,版本,語言,公鑰標記)。
例如.NET 2.0中的FileIOPermission類,它的強名稱是:
System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
對於弱命名的程序集,則只會有程序集名稱,而不會有版本,語言和公鑰標記。如 TestClassLibrary
2. Assembly.LoadFrom()
LoadFrom()方法能夠從指定文件中加載程序集,經過查找程序集的AssemblyRef元數據表,得知全部引用和須要的程序集,而後在內部調用Load()方法進行加載。
Assembly.LoadFrom(@"C:\ABC\Test.dll");
3. Assembly.LoadFile()
LoadFile()從一個指定文件中加載程序集,它和LoadFrom()的不一樣之處在於LoadFile()不會加載目標程序集所引用和依賴的其餘程序集。
您須要本身控制並顯示加載全部依賴的程序集
Assembly.Load()方法,Assembly.LoadFrom()方法,Assembly.LoadFile()方法的區別!
1:Assembly.Load()
這個方法經過程序集的長名稱(包括程序集名,版本信息,語言文化,公鑰標記)來加載程序集的,會加載此程序集引用的其餘程序集,
通常狀況下都應該優先使用 這個方法,他的執行效率比LoadFrom要高不少,並且不會形成重複加載的問題(緣由在第2點上說明)
使用這個方法的時候, CLR會應用必定的策略來查找程序集,實際上CLR按以下的順序來定位程序集:
⑴若是程序集有強名稱,在首先在全局程序集緩(GAC)中查找程序集。
⑵若是程序集的強名稱沒有正確指定或GAC中找不到,那麼經過配置文件中的<codebase>元素指定的URL來查找
⑶若是沒有指定強名稱或是在GAC中找不到,CLR會探測特定的文件夾:
假設你的應用程序目錄是C:\AppDir,<probing>元素中的privatePath指定了一個路徑Path1,你要定位的程序集是AssemblyName.dll則CLR將按照以下順序定位程序集
C:\AppDir\AssemblyName.dll
C:\AppDir\AssemblyName\AssemblyName.dll
C:\AppDir\Path1\AssemblyName.dll
C:\AppDir\Path1\AssemblyName\AssemblyName.dll
若是以上方法不能找到程序集,會發生編譯錯誤,若是是動態加載程序集,會在運行時拋出異常!
2:Assembly.LoadFrom()
這個方法從指定的路徑來加載程序集,實際上這個方法被調用的時候,CLR會打開這個文件,獲取其中的程序集版本,語言文化,公鑰標記等信息,把他們傳遞給 Load方法,
接着,Load方法採用上面的策略來查找程序集。若是找到了程序集,會和LoadFrom方法中指定的路徑作比較,若是路徑相同,該程序集會被認爲是應用程序的一部分,
若是路徑不一樣或Load方法沒有找到程序集,那該程序集只是被做爲一個「數據文件」來加載,不會被認爲是應用程序的一部分。
這就是在第1點中提到的Load方法比LoadFrom方法的執行效率高的緣由。
另外,因爲可能把程序集做爲「數據文件」來加載,因此使用 LoadFrom從不一樣路徑加載相同程序集的時候會致使重複加載。固然這個方法會加載此程序集引用的其餘程序集。
3:Assembly.LoadFile()
這個方法是從指定的文件來加載程序集,和上面方法的不一樣之處是這個方法不會加載此程序集引用的其餘程序集!
結論:通常你們應該優先選擇Load方法來加載程序集,若是遇到須要使用LoadFrom方法的時候,最好改變設計而用Load方法來代替!
另:Assembly.LoadFile 與 Assembly.LoadFrom的區別
一、Assembly.LoadFile只載入相應的dll文件,好比Assembly.LoadFile("abc.dll"),則載入abc.dll,假如abc.dll中引用了def.dll的話,def.dll並不會被載入。
Assembly.LoadFrom則不同,它會載入dll文件及其引用的其餘dll,好比上面的例子,def.dll也會被載入。
二、用Assembly.LoadFrom載入一個Assembly時,會先檢查前面是否已經載入過相同名字的Assembly,好比abc.dll有兩個版本(版本1在目錄1下,版本2放在目錄2下),
程序一開始時載入了版本1,當使用Assembly.LoadFrom("2\\abc.dll")載入版本2時,不能載入,而是返回版本1。
Assembly.LoadFile的話則不會作這樣的檢查,好比上面的例子換成Assembly.LoadFile的話,則能正確載入版本2。
LoadFile:加載指定路徑上的程序集文件的內容。LoadFrom: 根據程序集的文件名加載程序集文件的內容。
區別:
LoadFile 方法用來來加載和檢查具備相同標識但位於不一樣路徑中的程序集.但不會加載程序的依賴項。
LoadFrom 不能用於加載標識相同但路徑不一樣的程序集。