反射用于在程序運行過程中,獲取類里面的信息或發現程序集并運行的一個過程。通過反射可以獲得.dll和.exe后綴的程序集里面的信息。使用反射可以看到一個程序集內部的類,接口,字段,屬性,方法,特性等信息。
先定義一個類
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Consoleapplication2{ [Serializable] class Poster { PRivate int count; public string OwnerName { get; set; } public string Title { get; set; } public string Content { get; set; } public void makePoster(string titile,string content) { Title = titile; Content = content; } public string getPoster() { return "Title: "+Title+" Content: " +Content +" postby"+OwnerName; } public string getPoster(string s) { return s; } }}
1.獲得Type對象
Type t1 = Type.GetType("ConsoleApplication2.Poster"); Type t2 = typeof(ConsoleApplication2.Poster);
Poster p = new Poster(); Type t3 = p.GetType();
2.通過System.Reflection.Assembly類
- 通過Assembly可以動態加載程序集,并查看程序集的內部信息,其中最常用的就是Load()這個方法。
Assembly assembly = Assembly.Load("MyAssembly");注意在Assembly里面的加載程序集有3個方法,分別是Load、LoadFrom和LoadFile。這3個方法有什么異同呢?
1、如果你引用了命名空間,那么就直接Load()方法,參數里面寫上命名空間+類名就可以加載了。
2、如果僅僅知道一個dll文件的那么就要用LoadFrom()方法了,參數里面直接填寫完整的路徑。
LoadFrom 方法具有以下缺點。請考慮改用 Load。
-如果已加載一個具有相同標識的程序集,則即使指定了不同的路徑,LoadFrom 仍返回已加載的程序集。
-如果用 LoadFrom 加載一個程序集,隨后加載上下文中的一個程序集嘗試加載具有相同顯示名稱的程序集,則加載嘗試將失敗。對程序集進行反序列化時,可能發生這種情況。總結: LoadFrom只能用于加載不同標識的程序集, 也就是唯一的程序集, 不能用于加載標識相同但路徑不同的程序集。
3、LoadFile (加載指定路徑上的程序集文件的內容。)
這個方法是從指定的文件來加載程序集,它是調用外部的API實現的加載方式,和上面Load,LoadFrom方法的不同之處是這個方法不會加載此程序集引用的其他程序集,也就是不會加載程序的依賴項。而同時也是不能加載相同標識的程序集的。
利用Assembly的object CreateInstance(string)方法可以反射創建一個對象,參數0為類名。
3.System.Reflection常用類
類型 作用 Assembly 通過此類可以加載操縱一個程序集,并獲取程序集內部信息 EventInfo 該類保存給定的事件信息 FieldInfo 該類保存給定的字段信息 MethodInfo 該類保存給定的方法信息 MemberInfo 該類是一個基類,它定義了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多個公用行為 Module 該類可以使你能訪問多個程序集中的給定模塊 ParameterInfo 該類保存給定的參數信息 PropertyInfo 該類保存給定的屬性信息
4.反射方法
參看3小結表列表中的MethodInfo,在調用方法時候注意是否重載,下面代碼表示了在相同方法名稱,不同簽名的情況下方法的獲取,一般來說如果只有一個方法只需使用
GetMethod(“方法的名稱”)
private static void rec() { Poster pp = new Poster(); Type p = Type.GetType("ConsoleApplication2.Poster"); Console.WriteLine(p.ToString()); Type p2 = typeof(ConsoleApplication2.Poster); Console.WriteLine(p2.ToString()); Console.WriteLine(pp.GetType().ToString()); string path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "ConsoleApplication2.exe"; Assembly ss = Assembly.LoadFrom(path); Console.WriteLine(ss.GetType("ConsoleApplication2.Poster").ToString() + "4"); Module mod = ss.GetModules()[0]; Console.WriteLine(mod.GetType("ConsoleApplication2.Poster").ToString() + "5"); //以上是加載的各種方法 MethodInfo[] methodList = p.GetMethods(); foreach (MethodInfo info in methodList) { Console.WriteLine(info.ToString());//方法列表 } object object_p = Activator.CreateInstance(p);//實例化一個對象 Type[] types = new Type[1]; types[0] = typeof(string); MethodInfo meth = p.GetMethod("getPoster", types);//獲取getPoser(string s)方法 object[] ob = new object[1];//傳入參數 ob[0] = "good dog"; Console.WriteLine(meth.Invoke(object_p, ob));//調用該方法 Type[] types2 = new Type[0]; MethodInfo meth2 = p.GetMethod("getPoster",types2); //獲取getPoster()方法 Console.WriteLine(meth2.Invoke(object_p,null)); }
結果為如下

這里可以看到屬性的生成方法。反射得到方法的列表默認是public的方法
5.反射屬性
反射屬性的獲得是用列表中的PropertyInfo,和方法的書寫格式基本一樣,一個GetProperties針對枚舉,一個是GetProperty針對個例,通過SetValue和GetValue進行賦值和取值
輸出結果為private static void rec2() { Type p = Type.GetType("ConsoleApplication2.Poster");//獲得反射對象 Console.WriteLine(p.ToString()); PropertyInfo[] p_info = p.GetProperties();//獲得反射的所有公開屬性 foreach (PropertyInfo p_in in p_info) { Console.WriteLine(p_in.ToString()); } object p_r = Activator.CreateInstance(p);//創建一個實例 PropertyInfo ptile = p.GetProperty("Title");//獲得Title屬性 ptile.SetValue(p_r, "這個是主題");//設置屬性值 Console.WriteLine( ptile.GetValue(p_r).ToString());//獲得屬性值 }
6.屬性和方法的綜合用例
為屬性復制,取值,通過方法進行處理
private static void ATest() { Type poster=typeof(ConsoleApplication2.Poster); object newposter = Activator.CreateInstance(poster); PropertyInfo p_owner = poster.GetProperty("OwnerName"); p_owner.SetValue(newposter, " Keith"); //為用戶賦值 MethodInfo p_make = poster.GetMethod("makePoster");//獲得makePoster方法 object[] para = new object[2]; para[0] = "天氣"; para[1] = "北京的天氣最近真的很差啊"; p_make.Invoke(newposter, para);//傳入參數 Type[] types = new Type[0]; MethodInfo p_getposter = poster.GetMethod("getPoster", types);//獲得getPoster方法注意和獲得makePoster不同 Console.WriteLine(p_getposter.Invoke(newposter,null));//輸出 }輸出結果
private static void setPosterRec() { Dictionary<string,string> oneposter=new Dictionary<string,string>(); oneposter.Add("OwnerName", "Keith"); oneposter.Add("Title","回復Rita"); oneposter.Add("Content","確實不怎么樣這天氣"); Type poster = typeof(ConsoleApplication2.Poster); object newposter = Activator.CreateInstance(poster); PropertyInfo[] pinfo = poster.GetProperties(); foreach (PropertyInfo p in pinfo) { if (oneposter.ContainsKey(p.Name)) { p.SetValue(newposter, Convert.ChangeType(oneposter[p.Name], p.PropertyType)); } } Poster thisp = newposter as Poster; Console.WriteLine(thisp.getPoster()); }7.模擬屬性值批量賦值
private static void setPosterRec() { Dictionary<string,string> oneposter=new Dictionary<string,string>(); oneposter.Add("OwnerName", "Keith"); oneposter.Add("Title","回復Rita"); oneposter.Add("Content","確實不怎么樣這天氣"); //假設數據來自xml Type poster = typeof(ConsoleApplication2.Poster); object newposter = Activator.CreateInstance(poster); PropertyInfo[] pinfo = poster.GetProperties();//獲得屬性列表 foreach (PropertyInfo p in pinfo) { if (oneposter.ContainsKey(p.Name)) {//枚舉屬性列表根據屬性的名字和字典key值相同的賦值 p.SetValue(newposter, Convert.ChangeType(oneposter[p.Name], p.PropertyType)); //Convert.ChangeType(oneposter[p.Name], p.PropertyType),根據反射的對象類型進行賦值 } } Poster thisp = newposter as Poster; Console.WriteLine(thisp.getPoster()); }
這段代碼有一個關鍵的地方就是Convert.ChangeType(oneposter[p.Name], p.PropertyType) 這里將字典中value轉換為類Poster中相同的類型,否則在賦值的時候會報錯
輸出結果
8.讀取類中的字段和特性
Poster中有一個私有字段Count,我們來把他變化一下輸出,特性的輸出用GetCustomAttribute
private static void getprivateRec() { Type poster = typeof(ConsoleApplication2.Poster); object newposter = Activator.CreateInstance(poster); /*FieldInfo 讀取類中的字段,第一個是字段名稱,后面是枚舉參數值,包括private和public*/ FieldInfo file = poster.GetField("count",BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); /*后面的和屬性一樣*/ file.SetValue(newposter, 200); Console.WriteLine(file.GetValue(newposter)); /*這里是輸出特性*/ object[] typeAttribute = poster.GetCustomAttributes(false); foreach (object a in typeAttribute) { Console.WriteLine(a.ToString()); } }輸出結果
新聞熱點
疑難解答