談談對C#中反射的一些理解和認識(上)


  今天就平常用到的非常多的反射這個技術來做一個總結,當然關於反射需要講解的東西實在是太多的內容,在一片文章中想要講解清楚是非常難的,本篇博客也是就自己本人對這些內容學習后的一個總結,當然包括看書和自己寫過的一些代碼中抽取的一些示例,而且本文也僅限於此時對於這個知識點的理解,希望通過以后的逐步學習能夠不斷加深對這個知識點的理解。

  首先來看看對於反射的基礎知識點。

       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);
        }
    }
}

    E 還可以通過反射來獲取屬性或者類上的特性

    有時候我們需要在類或者屬性上面添加自定義的特性,並且通過反射能夠獲取到這些特性,那么這個時候我們就可以使用反射來達到目的了。

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
{
	
    /// <summary>
    /// 自定義特性 屬性或者類可用  支持繼承
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true)]
    public class EnitityMappingAttribute : Attribute
    {
        private string tableName;
        /// <summary>
        /// 實體實際對應的表名
        /// </summary>
        public string TableName
        {
            get { return tableName; }
            set { tableName = value; }
        }

        private string columnName;
        /// <summary>
        /// 中文列名
        /// </summary>
        public string ColumnName
        {
            get { return columnName; }
            set { columnName = value; }
        }
    }

    /// <summary>
    /// 會員 ,實際的表名叫MemberInfo,並不是和實體名一致
    /// </summary>
    [EnitityMapping(TableName = "MemberInfo")]
    public class Member
    {
        private int id;
        [EnitityMapping(ColumnName = "關鍵字")]
        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        private string userName;
        [EnitityMapping(ColumnName = "會員注冊名")]
        public string UserName
        {
            get { return userName; }
            set { userName = value; }
        }

        private string realName;
        [EnitityMapping(ColumnName = "會員真實名")]
        public string RealName
        {
            get { return realName; }
            set { realName = value; }
        }

        private bool isActive;
        /// <summary>
        /// 是否活躍  沒有附加自定義屬性
        /// </summary>
        public bool IsActive
        {
            get { return isActive; }
            set { isActive = value; }
        }
    }    

    class Program
	{
        /// <summary>
        /// 通過反射取自定義屬性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        private static void DisplaySelfAttribute<T>() where T : class, new()
        {
            string tableName = string.Empty;
            List<string> listColumnName = new List<string>();
            Type objType = typeof(T);
            //取屬性上的自定義特性
            foreach (PropertyInfo propInfo in objType.GetProperties())
            {
                object[] objAttrs = propInfo.GetCustomAttributes(typeof(EnitityMappingAttribute), true);
                if (objAttrs.Length > 0)
                {
                    EnitityMappingAttribute attr = objAttrs[0] as EnitityMappingAttribute;
                    if (attr != null)
                    {
                        listColumnName.Add(attr.ColumnName); //列名
                    }
                }
            }

            //取類上的自定義特性
            object[] objs = objType.GetCustomAttributes(typeof(EnitityMappingAttribute), true);
            foreach (object obj in objs)
            {
                EnitityMappingAttribute attr = obj as EnitityMappingAttribute;
                if (attr != null)
                {
                    tableName = attr.TableName;//表名只有獲取一次
                    break;
                }
            }
            if (string.IsNullOrEmpty(tableName))
            {
                tableName = objType.Name;
            }
            Console.WriteLine(string.Format("The TableName of the entity is:{0} ", tableName));
            if (listColumnName.Count > 0)
            {
                Console.WriteLine("The Columns of the table are as follows:");
                foreach (string item in listColumnName)
                {
                    Console.WriteLine(item);
                }
            }
        }

        static void Main()
		{
            DisplaySelfAttribute<Member>(); //顯示結果
            Console.ReadLine();
		}
	}
}

  最終呈現的效果:

  這里簡單說一下AttributeUsage的一些用法,AttributeUsage 有三個 屬性 ,分別是 

           public bool AllowMultiple { get; set; }   作用:是否能在一個目標身上多次使用

           public bool Inherited { get; set; } 作用 :特性是否能繼承到子類身上

           public AttributeTargets ValidOn { get; } 作用:設置特性的可使用范圍

  這里面就是要解釋一下AttributeTargets 的特性使用范圍,這個主要是用在繼承自Attribute的子類里面,在本例中我們自定義的特性主要用於標識類和屬性

public enum AttributeTargets  
   {  
       // 摘要:  
       //     可以對程序集應用特性。  
       Assembly = 1,  
       //  
       // 摘要:  
       //     可以對模塊應用特性。  
       Module = 2,  
       //  
       // 摘要:  
       //     可以對類應用特性。  
       Class = 4,  
       //  
       // 摘要:  
       //     可以對結構應用特性,即值類型。  
       Struct = 8,  
       //  
       // 摘要:  
       //     可以對枚舉應用特性。  
       Enum = 16,  
       //  
       // 摘要:  
       //     可以對構造函數應用特性。  
       Constructor = 32,  
       //  
       // 摘要:  
       //     可以對方法應用特性。  
       Method = 64,  
       //  
       // 摘要:  
       //     可以對屬性應用特性。  
       Property = 128,  
       //  
       // 摘要:  
       //     可以對字段應用特性。  
       Field = 256,  
       //  
       // 摘要:  
       //     可以對事件應用特性。  
       Event = 512,  
       //  
       // 摘要:  
       //     可以對接口應用特性。  
       Interface = 1024,  
       //  
       // 摘要:  
       //     可以對參數應用特性。  
       Parameter = 2048,  
       //  
       // 摘要:  
       //     可以對委托應用特性。  
       Delegate = 4096,  
       //  
       // 摘要:  
       //     可以對返回值應用特性。  
       ReturnValue = 8192,  
       //  
       // 摘要:  
       //     可以對泛型參數應用特性。  
       GenericParameter = 16384,  
       //  
       // 摘要:  
       //     可以對任何應用程序元素應用特性。  
       All = 32767,  
   }  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM