1..NET反射的概述 .NET反射是審查元數(shù)據(jù)并動態(tài)收集關(guān)于它的類型信息的能力。 應(yīng)用程序結(jié)構(gòu)分為應(yīng)用程序域—程序集—模塊—類型—成員幾個層次,公共語言運行庫加載器管理應(yīng)用程序域。這些域在擁有相同應(yīng)用程序范圍的對象周圍形成了確定邊界。 這種管理包括將每個程序集加載到相應(yīng)的應(yīng)用程序域以及控制每個程序集中類型層次結(jié)構(gòu)的內(nèi)存布局,。程序集包含模塊,而模塊包含類型,類型又包含成員,,反射則提供了封裝程序集、模塊和類型的對象,。 我們可以使用反射動態(tài)地創(chuàng)建類型的實例,,將類型綁定到現(xiàn)有對象或從現(xiàn)有對象中獲取類型,然后調(diào)用類型的方法或訪問其字段和屬性,。
反射的層次模型:
2..NET反射的作用和應(yīng)用
(1).可以使用反射動態(tài)地創(chuàng)建類型的實例,,將類型綁定到現(xiàn)有對象,或從現(xiàn)有對象中獲取類型,; (2).應(yīng)用程序需要在運行時從某個特定的程序集中載入一個特定的類型,,以便實現(xiàn)某個任務(wù)時可以用到反射; (3).反射主要應(yīng)用與類庫,,這些類庫需要知道一個類型的定義,,以便提供更多的功能; (4).在.NET中實現(xiàn)工廠模式會使用反射較多,; (5).在JavaScript等語言編譯器使用反射來構(gòu)造符號表; (6).反射也可用于創(chuàng)建稱為類型瀏覽器的應(yīng)用程序,,使用戶能夠選擇類型,然后查看有關(guān)選定類型的信息; (7).System.Runtime.Serialization命名空間中的類使用反射來訪問數(shù)據(jù)并確定要永久保存的字段,; (8).System.Runtime.Remoting命名空間中的類通過序列化來間接地使用反射,。
3..NET反射的性能
使用反射來調(diào)用類型或者觸發(fā)方法,或者訪問一個字段或者屬性時clr 需 要做更多的工作:校驗參數(shù),,檢查權(quán)限等等,,所以速度是非常慢的。 所以盡量不要使用反射進(jìn)行編程,對于打算編寫一個動態(tài)構(gòu)造類型(晚綁定)的應(yīng)用程序,,可以采取以下的幾種方式進(jìn)行代替:
(1).通過類的繼承關(guān)系 讓該類型從一個編譯時可知的基礎(chǔ)類型派生出來,,在運行時生成該類 型的一個實例,將對其的引用放到其基礎(chǔ)類型的一個變量中,,然后調(diào)用該基礎(chǔ)類型的虛方法,。
(2).通過接口實現(xiàn) 在運行時,構(gòu)建該類型的一個實例,,將對其的引用放到其接口類型的一個變量中,,然后調(diào)用該接口定義的虛方法。
(3).通過委托實現(xiàn) 讓該類型實現(xiàn)一個方法,,其名稱和原型都與一個在編譯時就已知的委托相符,。 在運行時先構(gòu)造該類型的實例,然后在用該方法的對象及名稱構(gòu)造出該委托的實例,,接著通過委托調(diào)用你想要的方法,。這個方法相對與前面兩個方法所作的工作要多一些,效率更低一些,。 提高反射的性能:反射的性能損失主要來源于比較類型,、遍歷成員、調(diào)用成員三種情形,,其中比較類型耗時最小。 調(diào)用成員耗時最多,,所以盡量減少采用成員動態(tài)調(diào)用等反射方式可以提高應(yīng)用程序性能,。除此之外,采取后期綁定,、避免將反射方法放到循環(huán)內(nèi)產(chǎn)生放大效應(yīng)等辦法均可提升反射性能,。
4..NET反射常用類型 System.reflection命名空間下常用類型,允許你反射(解析)這些元數(shù)據(jù)表的代碼和反射相關(guān)的命名空間(可以通過這幾個命名空間訪問反射信息):
(1).System.Reflection.Assembly 使用Assembly定義和加載程序集,,加載在程序集清單中列出模塊,,以及從此程序集中查找類型并創(chuàng)建該類型的實例??梢允褂肁ssembly.Load和Assembly.LoadFrom方法動態(tài)地加載程序集,。
(2).System.Reflection.Module 使用Module了解包含模塊的程序集以及模塊中的類等,還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法,。
(3).System.Reflection.ConstructorInfo 使用ConstructorInfo了解構(gòu)造函數(shù)的名稱,、參數(shù)、訪問修飾符(如pulic 或private)和實現(xiàn)詳細(xì)信息(如abstract或virtual)等,。使用Type的GetConstructors或GetConstructor方法來調(diào)用特定的構(gòu)造函數(shù),。
(4).System.Reflection.MethodInfo 使用MethodInfo了解方法的名稱、返回類型、參數(shù),、訪問修飾符(如pulic 或private)和實現(xiàn)詳細(xì)信息(如abstract或virtual)等,。使用Type的GetMethods或GetMethod方法來調(diào)用特定的方法。 (5).System.Reflection.FieldInfo 使用FieldInfo了解字段的名稱,、訪問修飾符(如public或private)和實現(xiàn)詳細(xì)信息(如static)等,,并獲取或設(shè)置字段值。
(6).System.Reflection.EventInfo 使用EventInfo了解事件的名稱,、事件處理程序數(shù)據(jù)類型,、自定義屬性、聲明類型和反射類型等,,添加或移除事件處理程序,。 (7).System.Reflection.PropertyInfo 使用PropertyInfo了解屬性的名稱、數(shù)據(jù)類型,、聲明類型,、反射類型和只讀或可寫狀態(tài)等,獲取或設(shè)置屬性值,。
(8).System.Reflection.ParameterInfo 使用ParameterInfo了解參數(shù)的名稱,、數(shù)據(jù)類型、是輸入?yún)?shù)還是輸出參數(shù),,以及參數(shù)在方法簽名中的位置等,。 System.Reflection.Emit命名空間的類提供了一種特殊形式的反射,可以在運行時構(gòu)造類型,。
(9).System.Type System.Type類是一個抽象類,,代表公用類型系統(tǒng)中的一種類型。這個類使您能夠查詢類型名,、類型中包含的模塊和名稱空間,、以及該類型是一個數(shù)值類型還是一個引用類型。 System.Type類使您能夠查詢幾乎所有與類型相關(guān)的屬性,,包括類型訪問限定符,、類型是否、類型的COM屬性等等,。
(10).System.Activator Activator類支持動態(tài)創(chuàng)建.NET程序集和COM對象,。可以通過CreateComInstanceFrom,、CreateInstance,、CreateInstanceFrom、GetObject四個靜態(tài)方法加載COM對象或者程序集,,并能創(chuàng)建指定類型的實例,。
使用注意: (1).Load方法:極力推薦的一種方法,,Load 方法帶有一個程序集標(biāo)志并載入它,Load 將引起CLR把策略應(yīng)用到程序集上,。 先后在全局程序集緩沖區(qū),,應(yīng)用程序基目錄和私有路徑下面查找該程序集,,如果找不到該程序集系統(tǒng)拋出異常,。
(2).LoadFrom方法:傳遞一個程序集文件的路徑名(包括擴(kuò)展名),CLR會載入您指定的這個程序集,,傳遞的這個參數(shù)不能包含任何關(guān)于版本號的信息,,區(qū)域性,和公鑰信息,,如果在指定路徑找不到程序集拋出異常,。
(3).LoadWithPartialName:永遠(yuǎn)不要使用這個方法,因為應(yīng)用程序不能確定再在載入的程序集的版本,。該方法的唯一用途是幫助那些在.Net框架的測試環(huán)節(jié)使用.net 框架提供的某種行為的客戶,,這個方法將最終被拋棄不用。
5..NET反射示例Demo
(1).代碼結(jié)構(gòu)
(2).TestClassLib類庫的Arithmetic類
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace TestClassLib { /// /// 定義示例接口Iwel /// public interface Iwel { string Print(); }
/// /// 構(gòu)造測試數(shù)據(jù)類 /// public class Arithmetic:Iwel { //定義私有變量 private int numOne; private int numTwo;
#region 構(gòu)造函數(shù)測試 //不帶參數(shù)的構(gòu)造函數(shù) public Arithmetic() { }
//帶參數(shù)構(gòu)造函數(shù),,初始化numOne和numTwo public Arithmetic(int intNumOne, int intNumTwo) { this.numOne = intNumOne; this.numTwo = intNumTwo; } #endregion
#region 屬性測試 //公共屬性訪問NumOne public int NumOne { get { return numOne; } set { numOne = value; } }
//公共屬性 訪問NumTwo public int NumTwo { get { return numTwo; } set { numTwo = value; } } #endregion
#region 方法測試 /// /// 私有非靜態(tài)不帶參數(shù)的方法 /// /// private string Add() { return 'Add()方法是一個私有不帶參數(shù)的方法'; }
/// /// 私有靜態(tài)帶參數(shù)無返回值的方法 /// /// private static void Multiplcation(int intNumOne) { Console.WriteLine('Multiplication()方法是一個私有不帶參數(shù)無返回值的靜態(tài)方法'); }
/// /// 私有非靜態(tài)帶參數(shù)的方法 /// /// /// private void Subtration(int intNumOne, int intNumTwo) { string strMeesage = '{0}-{1}={2} Subtration(int intNumOne, int intNumTwo)方法是一個私有帶參數(shù)的方法';
Console.WriteLine(strMeesage, intNumOne, intNumTwo, intNumOne - intNumTwo);
}
/// /// 公有非靜態(tài)不帶參數(shù)的方法 /// /// public void Write() { Console.WriteLine( 'Write() 是一個共有的不帶參數(shù)無返回值的方法'); }
/// /// 公有靜態(tài)帶參數(shù)的方法 /// /// /// public static string Multiplcation(int intNumOne, int intNumTwo) { string strMessage = '{0}*{1}={2} Multiplcation(int intNumOne,int intNumTwo)方法是一個公有的靜態(tài)帶參數(shù)的方法'; strMessage = string.Format('{0}*{1}={2}', intNumOne, intNumTwo, intNumOne * intNumTwo); return strMessage; }
/// /// 公有非靜態(tài)帶參數(shù)的方法 /// /// /// /// public string Add(int intNumOne,int intNumTwo) { string strMessage = string.Format('{0}+{1}={2}', intNumOne, intNumTwo, intNumOne + intNumTwo); return strMessage; } #endregion
/// /// 集成接口方法 /// /// public string Print() { return ' Print() 繼承接口方法'; } } }
(3).TestClassLib類庫的TestClass類
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace TestClassLib { public class TestClass { //模擬測試 public class Dialog : DialogInvoker { }
public virtual string TestMethod(string pp) { return pp; } } }
(4).TestClassLib類庫的DialogInvoker類 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace TestClassLib { public class DialogInvoker { public int TestInt; public void RegisterWithKey(string strOne,string strTwo) { Console.WriteLine('Test組合類:'+strOne+','+strTwo); } } }
(5).TestClassLib類庫的TestDialog類 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace TestClassLib { public class TestDialog { //模擬測試 public void OnInit() { new TestClass.Dialog().RegisterWithKey('PP', 'TT'); } } }
(6).ReflectTest的Program.cs代碼調(diào)用測試
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using TestClassLib;
namespace ReflectTest { class Program { //定義委托測試 delegate void TestDelegate(int intNumOne,int intNumTwo);
static void Main(string[] args) { SimpleTest();//簡單測試
TestArithmetic();//分析測試
TestDialog();//模擬測試
Console.ReadLine(); }
/// /// 基本簡單測試 /// static void SimpleTest() { //System.Reflection.Assembly ass = Assembly.Load('TestClassLib'); //加載DLL //System.Type t = ass.GetType('TestClassLib.TestChildrenClass');//獲得類型
string path = 'TestClassLib.TestClass' + ',' + 'TestClassLib';//命名空間.類型名,程序集 Type testType = Type.GetType(path);//加載類型
object objType = System.Activator.CreateInstance(testType);//創(chuàng)建實例 System.Reflection.MethodInfo methodReflection = testType.GetMethod('TestMethod');//獲得方法
object str = methodReflection.Invoke(objType, new object[] { 'MM' });//調(diào)用方法 Console.WriteLine('簡單測試輸出:'+str.ToString()); }
/// /// 反射分析測試 /// static void TestArithmetic() { string strAssembly = 'TestClassLib';//程序集DLL string strReflectClass = 'TestClassLib.Arithmetic';//命名空間.類型 string strMethodAdd = 'Add';//調(diào)用方法Add名稱 string strMethodWrite = 'Write';//調(diào)用方法Write名稱 string strMethodMul = 'Multiplcation';//調(diào)用方法Multiplcation名稱
Assembly AssTestClassLib = Assembly.Load(strAssembly);//得到程序集 Type ArithmeticClass = AssTestClassLib.GetType(strReflectClass);;//得到具體類型 //Type ArithmeticClass = Type.GetType(strReflectClass + ',' + strAssembly);//創(chuàng)建對象也可以使用:命名空間.類型名,程序集
#region 獲取程序集下的信息 Console.WriteLine('\n得到'+strAssembly+'中所有類:' ); foreach (Type type in AssTestClassLib.GetTypes()) { Console.WriteLine(type.Name+'是'+strAssembly+'命名空間下的對象'); } Console.WriteLine('\n得到'+strAssembly+'.dll中的模塊集:'); Module[] modules = AssTestClassLib.GetModules(); foreach (Module module in modules) { Console.WriteLine(module.Name+'是'+strAssembly+'下的模塊集'); } #endregion
#region 獲取指定類下的信息 Console.WriteLine('\n具體類型是'+ArithmeticClass.Name); Console.WriteLine('{0}是不是Public類型{1}',ArithmeticClass,ArithmeticClass.IsPublic); Console.WriteLine('{0}是不是Privet類型{1}',ArithmeticClass,ArithmeticClass.IsPrimitive);
Console.WriteLine('\n得到' + ArithmeticClass + '類下的構(gòu)造函數(shù):'); ConstructorInfo [] constructorInfos = ArithmeticClass.GetConstructors(); foreach (ConstructorInfo constructor in constructorInfos) { Console.WriteLine(constructor); }
Console.WriteLine('\n得到'+ArithmeticClass+'類下的所有屬性:'); PropertyInfo[] propertyInfos = ArithmeticClass.GetProperties(); foreach (PropertyInfo prop in propertyInfos) { Console.WriteLine(prop.Name+'是'+ArithmeticClass + '類下的屬性'); }
Console.WriteLine('\n得到'+ArithmeticClass+'類下所有的接口:'); Type[] typeInterfaces = ArithmeticClass.GetInterfaces(); foreach (Type typeInterface in typeInterfaces) { Console.WriteLine(typeInterface.Name+'是'+ArithmeticClass+'類下的接口'); }
#region 獲取所有方法的信息 Console.WriteLine('\n得到'+ArithmeticClass+'類下所有方法:'); //查找私有方法 MethodInfo[] methodPrivates = ArithmeticClass.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic); foreach (MethodInfo method in methodPrivates) { Console.WriteLine('私有方法 方法名稱:{0} 方法信息:{1}',method.Name,method); } //查找公有方法 MethodInfo[] methodPublics = ArithmeticClass.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo method in methodPublics) { Console.WriteLine('公有方法 方法名稱:{0} 方法信息:{1}', method.Name, method); } //查找私有靜態(tài)方法 MethodInfo[] methodStaticPrivates = ArithmeticClass.GetMethods(BindingFlags.NonPublic | BindingFlags.Static); foreach (MethodInfo method in methodStaticPrivates) { Console.WriteLine('私有靜態(tài)方法 方法名稱:{0} 方法信息:{1}', method.Name, method); } //查找公有靜態(tài)方法 MethodInfo[] methodStaticPublics = ArithmeticClass.GetMethods(BindingFlags.Public | BindingFlags.Static); foreach (MethodInfo method in methodPrivates) { Console.WriteLine('公有靜態(tài)方法 方法名稱:{0} 方法信息:{1}', method.Name, method); } #endregion #endregion
#region 創(chuàng)建對象實例 Console.WriteLine('\n創(chuàng)建對象實例:'); int num1 = 3, num2 = 5;//定義參數(shù)
//創(chuàng)建一個不帶參數(shù)的實例 object obj = Activator.CreateInstance(ArithmeticClass, null);
//公有非靜態(tài)帶參數(shù)和返回值的方法調(diào)用 MethodInfo methodAdd = ArithmeticClass.GetMethod(strMethodAdd); object[] addParams = new object[] {num1,num2 }; string strReturnAdd=methodAdd.Invoke(obj, addParams).ToString(); Console.WriteLine('創(chuàng)建{0}類,,調(diào)用公有非靜態(tài){1}方法,傳入?yún)?shù){2}和{3},,返回值:{4}',ArithmeticClass, strMethodAdd, num1, num2, strReturnAdd);
//私有非靜態(tài)無參無返回值方法調(diào)用 MethodInfo methodStaticAdd = ArithmeticClass.GetMethod(strMethodAdd, BindingFlags.Instance | BindingFlags.NonPublic); string strStaticAdd=methodStaticAdd.Invoke(obj,null).ToString(); Console.WriteLine('創(chuàng)建{0}類,調(diào)用私有非靜態(tài){1}方法,,返回值:{2}:', ArithmeticClass, strMethodAdd, strStaticAdd);
//公有非靜態(tài)無參數(shù)無返回值方法調(diào)用 MethodInfo methodWite = ArithmeticClass.GetMethod(strMethodWrite, BindingFlags.Instance | BindingFlags.Public); Console.WriteLine('創(chuàng)建{0}類,,調(diào)用公有非靜態(tài){1}方法,,無參數(shù)無返回值:', ArithmeticClass, strMethodWrite, methodWite.Invoke(obj, null));
//公有靜態(tài)帶參數(shù)有返回值的方法調(diào)用 MethodInfo methodMultiplcation = ArithmeticClass.GetMethod(strMethodMul, BindingFlags.Public | BindingFlags.Static); object[] multParams = new object[] { num1, num2 }; string multReturn = methodMultiplcation.Invoke(obj, multParams).ToString(); //string multReturn = methodMultiplcation.Invoke(null, multParams).ToString();//調(diào)用靜態(tài)方法也可以轉(zhuǎn)入null對象 Console.WriteLine('創(chuàng)建{0}類,,調(diào)用公有靜態(tài){1}方法,傳入?yún)?shù){2}和{3},返回值:{4}', ArithmeticClass, strMethodMul, num1, num2, multReturn);
//測試InvokeMember方法 object objReturn= ArithmeticClass.InvokeMember(strMethodAdd, BindingFlags.InvokeMethod, null, obj,new object[]{num1,num2}); Console.WriteLine('測試InvokeMember方法:創(chuàng)建{0}類,,調(diào)用公有靜態(tài){1}方法,,傳入?yún)?shù){2}和{3},返回值:{4}:' , ArithmeticClass, strMethodAdd, num1, num2, objReturn.ToString()); #endregion
//動態(tài)創(chuàng)建委托 Console.WriteLine('\n動態(tài)創(chuàng)建委托:'); TestDelegate testDel = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, 'Subtration'); testDel(9,3); }
/// /// 模擬測試 /// static void TestDialog() { string strAssembly = 'TestClassLib';//程序集DLL string strDialogReflect = 'TestClassLib.TestDialog'; string strDialogInvokerReflect = 'TestClassLib.DialogInvoker'; string strDialogNestedTypeReflect = 'TestClassLib.TestClass';//嵌套如何關(guān)系類,命名空間.類 string strNestedType = 'Dialog';//嵌套組合類 string strDialogMethod = 'OnInit'; string strDialogInvokerMethod = 'RegisterWithKey';
Console.WriteLine('\n模擬測試:');
Assembly assemblyTest = Assembly.Load(strAssembly);
//間接調(diào)用 Type typeDialog = assemblyTest.GetType(strDialogReflect); object objDialog = Activator.CreateInstance(typeDialog); MethodInfo methodDialog = typeDialog.GetMethod(strDialogMethod); methodDialog.Invoke(objDialog, null);
//直接調(diào)用 Type typeDialogInvoker = assemblyTest.GetType(strDialogInvokerReflect); object objDialogInvoker = Activator.CreateInstance(typeDialogInvoker); MethodInfo methodDialogInvoker = typeDialogInvoker.GetMethod(strDialogInvokerMethod); methodDialogInvoker.Invoke(objDialogInvoker, new object[] { 'MM', 'KK' });
//使用嵌套組合關(guān)系調(diào)用(這個更實用) var typeTestClass =assemblyTest.GetType(strDialogNestedTypeReflect); //var typeTestClass = Assembly.GetExecutingAssembly().GetType(strDialogNestedTypeReflect);//如果在同一個程序集下可以使用這種方式 var testClass= Activator.CreateInstance(typeTestClass);//創(chuàng)建本類
var typeNestedDialog= typeTestClass.GetNestedType(strNestedType);//獲取嵌套組合類 var dialogClass = Activator.CreateInstance(typeNestedDialog);//創(chuàng)建嵌套組合類 var methodInfo = dialogClass.GetType().GetMethod(strDialogInvokerMethod, BindingFlags.Instance | BindingFlags.Public); methodInfo.Invoke(dialogClass, new object[] {'TT','KK' }); } } }
6.運行效果如下:
原文出自:博客園-SanMaoSpace 原文鏈接:http://www.cnblogs.com/SanMaoSpace/p/3764953.html
|