C# 中那些常用的工具類(Utility Class)(三)
今天就平常用到的非常多的反射這個技術來做一個總結,當然關於反射需要講解的東西實在是太多的內容,在一片文章中想要講解清楚是非常難的,本篇博客也是就自己本人對這些內容學習後的一個總結,當然包括看書和自己寫過的一些代碼中抽取的一些示例,而且本文也僅限於此時對於這個知識點的理解,希望通過以後的逐步學習能夠不斷加深對這個知識點的理解。
首先來看看對於反射的基礎知識點。
1 定義:首先看看MSDN怎樣對它進行解釋吧
反射提供了封裝程序集、模塊和類型的對象(Type 類型)。可以使用反射動態創建類型的實例,將類型綁定到現有對象,或從現有對象獲取類型並調用其方法或訪問其字段和屬性。如果代碼中使用了屬性,可以利用反射對它們進行訪問。
2 反射有什麽作用?
A、將類型綁定到現有對象,或從現有對象中獲取類型信息,這些信息包括(Assembly MemberInfo EventInfo FieldInfo MethodBase ConstructorInfo MethodInfo PropertyInfo 等等 )另外可以使用反射動態地創建類型的實例,
例如:
1、System.Activator 的CreateInstance方法。該方法返回新對象的引用。
2、System.Activator 的CreateInstanceFrom 與上一個方法類似,不過需要指定類型及其程序集
3、System.Appdomain 的方法:CreateInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap
4、System.Type的InvokeMember 實例方法:這個方法返回一個與傳入參數相符的構造函數,並構造該類型。
5、System.Reflection.Constructinfo 的Invoke實例方法
下面通過一段代碼來了解這5種創建實例的方法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Diagnostics; using OptimizeReflection; using System.Collections; using System.Web; namespace TestOptimizeReflection { public class OrderInfo { public int OrderID { get; set; } public DateTime OrderDate { get; set; } public decimal SumMoney { get; set; } public string Comment { get; set; } public bool Finished { get; set; } public int Add(int a, int b) { return a + b; } } class Program { static void Main() { TestNewInstance(); } static void TestNewInstance() { //常規方法創建對象 OrderInfo testObj = new OrderInfo(); #region 常規反射創建 //利用反射來動態創建對象 Type instanceType = typeof(OrderInfo); OrderInfo orderInfo = (OrderInfo)Activator.CreateInstance(instanceType); #endregion #region Activator.CreateInstanceFrom 創建 //註意Assembly.GetEntryAssembly().CodeBase表示當前執行的exe所在的路徑,instanceType.FullName表示當前OrderInfo的類型名稱TestOptimizeReflection.OrderInfo System.Runtime.Remoting.ObjectHandle oh= Activator.CreateInstanceFrom(Assembly.GetEntryAssembly().CodeBase, instanceType.FullName); //返回被包裝的對象 OrderInfo orderInfoEx = (OrderInfo)oh.Unwrap(); #endregion #region System.AppDomain.CurrentDomain實例創建對象 System.Runtime.Remoting.ObjectHandle ohEx = System.AppDomain.CurrentDomain.CreateInstance(Assembly.GetEntryAssembly().FullName, instanceType.FullName); OrderInfo orderInfoExEx = (OrderInfo)ohEx.Unwrap(); //合並上面的兩步 OrderInfo orderInfoExExEx = (OrderInfo)System.AppDomain.CurrentDomain.CreateInstanceAndUnwrap(Assembly.GetEntryAssembly().FullName, instanceType.FullName); #endregion #region InvokeMember方法創建實例 OrderInfo invokeMemberOrderInfo = (OrderInfo)instanceType.InvokeMember(null, BindingFlags.Public| BindingFlags.Instance | BindingFlags.Static|BindingFlags.CreateInstance, System.Type.DefaultBinder, null, null); #endregion #region 調用構造器創建 //調用無參數的默認構造函數 ConstructorInfo ci = instanceType.GetConstructor(new Type[] { }); OrderInfo ciOrderInfo = (OrderInfo)ci.Invoke(null); #endregion } } }
B、應用程序需要在運行時從某個特定的程序集中載入一個特定的類型,以便實現某個任務時可以用到反射。
這個該怎樣去理解呢?這個可以用插件系統中的同類思想去解釋,在構建插件系統的時候,我們有時候需要主程序去動態地調用插件,可能應用程序只有在執行某一操作的時候才能夠去調用相關的DLL,這個時候我們就可以通過反射這種方式來動態調用dll中分特定方法或者類型,這個也是經常使用到的。
C、反射主要應用與類庫,這些類庫需要知道一個類型的定義,以便提供更多的功能。
D、反射能夠調用一些私有方法和字段等。
這個需要重點去講述,我們知道常規的實例方法由於受到作用域的影響,很多時候當方法設置為Private或者是其它的限制訪問的關鍵字時就無能為力了,這個也是完全能夠體現類的封裝性,但是通過反射就能夠完全繞開這些限制,下面舉出一些對私有變量或字段、方法的一些訪問方式,能夠直接進行訪問,這樣還是非常方便的,具體請參考下面的代碼。
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Dvap.Infrastructure.Utils { public static class ReflectionUtil { /// <summary> /// 得到私有字段的值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="instance"></param> /// <param name="fieldname"></param> /// <returns></returns> public static T GetPrivateField<T>(this object instance, string fieldname) { BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; Type type = instance.GetType(); FieldInfo field = type.GetField(fieldname, flag); return (T)field.GetValue(instance); } /// <summary> /// 設置私有成員的值 /// </summary> /// <param name="instance"></param> /// <param name="fieldname"></param> /// <param name="value"></param> public static void SetPrivateField(this object instance, string fieldname, object value) { BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; Type type = instance.GetType(); FieldInfo field = type.GetField(fieldname, flag); field.SetValue(instance, value); } /// <summary> /// 得到私有屬性的值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="instance"></param> /// <param name="propertyname"></param> /// <returns></returns> public static T GetPrivateProperty<T>(this object instance, string propertyname) { BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; Type type = instance.GetType(); PropertyInfo field = type.GetProperty(propertyname, flag); return (T)field.GetValue(instance, null); } /// <summary> /// 設置私有屬性的值 /// </summary> /// <param name="instance"></param> /// <param name="propertyname"></param> /// <param name="value"></param> public static void SetPrivateProperty(this object instance, string propertyname, object value) { BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; Type type = instance.GetType(); PropertyInfo field = type.GetProperty(propertyname, flag); field.SetValue(instance, value, null); } /// <summary> /// 調用私有方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="instance"></param> /// <param name="name"></param> /// <param name="param"></param> /// <returns></returns> public static T CallPrivateMethod<T>(this object instance, string name, params object[] param) { BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; Type type = instance.GetType(); MethodInfo method = type.GetMethod(name, flag); return (T)method.Invoke(instance, param); } } }
C# 中那些常用的工具類(Utility Class)(三)