1、爲何要使用反射編程
程序集包含模塊,而模塊包含類型,類型又包含成員。反射則提供了封裝程序集、模塊和類型的對象。您可使用反射動態地建立類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。而後,能夠調用類型的方法或訪問其字段和屬性。瀏覽器
2、反射機制的原理安全
審查元數據並收集關於它的類型信息的能力。框架
元數據是一種二進制信息,用以對存儲在公共語言運行庫可移植可執行文件 (PE) 文件或存儲在內存中的程序進行描述。將您的代碼編譯爲 PE 文件時,便會將元數據插入到該文件的一部分中。函數
元數據以非特定語言的方式描述在代碼中定義的每一類型和成員。元數據存儲如下信息: 測試
3、反射的做用spa
反射一般具備如下用途:.net
使用 Assembly 定義和加載程序集,加載在程序集清單中列出的模塊,以及今後程序集中查找類型並建立該類型的實例。code
使用 Module 瞭解以下的相似信息:包含模塊的程序集以及模塊中的類等。您還能夠獲取在模塊上定義的全部全局方法或其餘特定的非全局方法。對象
使用 ConstructorInfo 瞭解如下信息:構造函數的名稱、參數、訪問修飾符(如public 或private)和實現詳細信息(如 abstract 或virtual)等。使用 Type 的 GetConstructors 或 GetConstructor 方法來調用特定的構造函數。
使用 MethodInfo 瞭解如下信息:方法的名稱、返回類型、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。使用 Type 的 GetMethods 或 GetMethod 方法來調用特定的方法。
使用 FieldInfo 瞭解如下信息:字段的名稱、訪問修飾符(如 public 或private)和實現詳細信息(如static)等;並獲取或設置字段值。
使用 EventInfo 來了解以下的相似信息:事件的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等;並添加或移除事件處理程序。
使用 PropertyInfo 來了解以下的相似信息:屬性的名稱、數據類型、聲明類型、反射類型和只讀或可寫狀態等;並獲取或設置屬性值。
使用 ParameterInfo 來了解以下的相似信息:參數的名稱、數據類型、參數是輸入參數仍是輸出參數,以及參數在方法簽名中的位置等。
當您在一個應用程序域的僅反射上下文中工做時,請使用 CustomAttributeData 來了解有關自定義屬性的信息。使用 CustomAttributeData,您沒必要建立屬性的實例就能夠檢查它們。
System.Reflection.Emit 命名空間的類提供了一種特殊形式的反射,使您可以在運行時構造類型。
反射也可用於建立稱做類型瀏覽器的應用程序,它使用戶可以選擇類型,而後查看有關選定類型的信息。
反射還有其餘一些用途。JScript 等語言編譯器使用反射來構造符號表。System.Runtime.Serialization 命名空間中的類使用反射來訪問數據並肯定要持久保存的字段。System.Runtime.Remoting 命名空間中的類經過序列化來間接地使用反射。
以上摘自http://msdn.microsoft.com/zh-cn/library/f7ykdhsy%28v=vs.80%29
4、一些小知識
一、類型(Type) 對象是什麼
好比 object x; x是對象,object就是它的類型,在程序中如何描述類型這個概念呢?就是Type(System.Type)。要獲取某個類的類型能夠用typeof()操做符
object a;object b;
DataTable t;
Type aType = typeof(object);Type bType = typeof(object);tType = typeof(DataTable);
aType==bType!=tType;
二、程序集(Assembly)
就是你IDE生成的.exe或.dll文件的運行時就叫程序集。全部的代碼都在程序集中。你能夠經過Assembly.Load()系列函數動態加載程序集(這一步是動態+載代碼的前提,由於全部的代碼都在程序集中)。
三、動態加載
咱們普通調用代碼是: 對象名.方法名(參數列表);
class a{
void func(int x){}
public static void Main(string[] args)
{
//建立對象
a a1 = new a();
//調用函數
a1.func(1);
}
}
用反射動態調用代碼是
//加載程序集
System.Reflection.Assembly asm = Assembly.LoadFile(assemblyPath);
//獲取類型
Type aType = asm.GetType( "名字空間.類名 ");
//獲取沒有參數的構造函數
System.Reflection.ConstructorInfo conn = t.GetConstructor(new Type[0]);
//調用沒有參數的構造函數,Invoke返回object它其是a類
object a1 = conn.Invoke(new object[0]);
//獲取參數類型爲int,函數名爲func的方法
MethodInfo method = t.GetMethod( "func ",new Type[]{typeof(int)});
//在a1上調用func方法,參數爲1
method.Invoke(a1,new object[]{1});
動態調用(後一種方法)比靜態調用更復雜,並且效率大概低20倍(網上有個哥們好像測試過)。只有在特殊的時候才調用動態加載動態調用---好比,你的主程序啓動的時候子模塊尚未,要根據登錄信息下載子模塊代碼並調用子模塊代碼,就只能用動態+載來實現了.
四、元數據
.net生成的IL代碼中標明瞭在這個(exe,dll)文件中全部的class(類) method(方法)Attribute(屬性) Property(類屬性)的簽名和調用方法信息,這些信息就叫作元數據。所謂的Reflection反射,就是利用元數據,能夠了解到某個assembly(基本等同文件)中的class。。。。。 (就是上面那一串咚咚)信息和調用方法。
五、.net framework
在.net framework中反射類基本都在System.Reflection中。System.Type是反射的核心類.
與它相關的還有System.Attribute命名空間。
5、實例
一、Assembly的使用
Assembly是一個包含來程序的名稱,版本號,自我描述,文件關聯關係和文件位置等信息的一個集合。在.net框架中經過Assembly類來支持,該類位於System.Reflection下,物理位置位於:mscorlib.dll。咱們能夠經過Assembly的信息來獲取程序的類,實例等編程須要用到的信息。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace ConsoleApplication5 { class Program { static void Main(string[] args) { People people;//這種使用方式能夠獲取相應類中的變量、方法等元素 string assemblyName = @"ConsoleApplication5"; string strongClassName = @"ConsoleApplication5.Male";//能夠把這裏的聲明看做是路徑:命名空間下的類名 people = (People)Assembly.Load(assemblyName).CreateInstance(strongClassName);//這裏也可使用Male或者Female變量來獲取相應的屬性及方法 Console.WriteLine(people.name); //Assembly ass = Assembly.Load(assemblyName);//這種使用方式能夠獲取程序的名稱,版本號,自我描述,文件關聯關係和文件位置等信息的一個集合 //Assembly ass1 = Assembly.LoadFrom(@"D:\work\myTest\myTest\bin\myTest.dll"); ////獲取程序集顯示名稱 //Console.WriteLine(ass1.FullName); ////獲取程序集中定義的類型 //Type[] types = ass.GetTypes(); //foreach (Type t in types) //{ // Console.WriteLine(t.FullName); //} Console.ReadKey(); } }
class People { public string name; } class Male : People { public Male() { name = "你好"; } public string sex = "男"; public string hello() { return "我是"+sex+"生"; } } class Female : People { public Female() { name = "Hello"; } public string sex = "女"; public string hello() { return "我是" + sex + "生"; } } }
二、Module的使用
三、ConstructorInfo 的使用
繼續試用上面的例子
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace ConsoleApplication5 { class Program { static void Main(string[] args) { Assembly ass = Assembly.Load("ConsoleApplication5"); Assembly ass1 = Assembly.LoadFrom(@"D:\work\myTest\myTest\bin\myTest.dll"); Type type = ass.GetType("ConsoleApplication5.People"); //將獲得的類型傳給一個新建的構造器類型變量 ConstructorInfo constructor = type.GetConstructor(new Type[0]); //使用構造器對象來建立對象 object obj = constructor.Invoke(new Object[0]); //輸出對象類型 Console.WriteLine(obj); } } }
四、MethodInfo 的使用
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace MethodInfoInvokeDemo { public class ReflectTest { public void MethodWithNoParaNoReturn() { Console.WriteLine("不帶參數且不返回值的方法"); } public string MethodWithNoPara() { Console.WriteLine("不帶參數且有返回值的方法"); return "MethodWithNoPara"; } public string Method1(string str) { Console.WriteLine("帶參數且有返回值的方法"); return str; } public string Method2(string str, int index) { Console.WriteLine("帶參數且有返回值的方法"); return str + index.ToString(); } public string Method3(string str, out string outStr) { outStr = "bbbb"; Console.WriteLine("帶參數且有返回值的方法"); return str; } public static string StaticMethod() { Console.WriteLine("靜態方法"); return "cccc"; } } class Program { static void Main(string[] args) { Type type = typeof(ReflectTest); object reflectTest = Activator.CreateInstance(type); //不帶參數且不返回值的方法的調用 MethodInfo methodInfo = type.GetMethod("MethodWithNoParaNoReturn"); methodInfo.Invoke(reflectTest, null); Console.WriteLine(); //不帶參數且有返回值的方法的調用 methodInfo = type.GetMethod("MethodWithNoPara"); Console.WriteLine(methodInfo.Invoke(reflectTest, null).ToString()); Console.WriteLine(); //帶參數且有返回值的方法的調用 methodInfo = type.GetMethod("Method1", new Type[] { typeof(string) }); Console.WriteLine(methodInfo.Invoke(reflectTest, new object[] { "測試" }).ToString()); Console.WriteLine(); //帶多個參數且有返回值的方法的調用 methodInfo = type.GetMethod("Method2", new Type[] { typeof(string), typeof(int) }); Console.WriteLine(methodInfo.Invoke(reflectTest, new object[] { "測試", 100 }).ToString()); //Console.WriteLine(); //methodInfo = type.GetMethod("Method3", new Type[] { typeof(string), typeof(string) }); //string outStr = ""; //Console.WriteLine(methodInfo.Invoke(reflectTest, new object[] { "測試", outStr }).ToString()); Console.WriteLine(); //靜態方法的調用 methodInfo = type.GetMethod("StaticMethod"); Console.WriteLine(methodInfo.Invoke(null, null).ToString()); Console.ReadKey(); } } }