1. 程式人生 > >理解C#反射機制

理解C#反射機制

反射是.NET中的重要機制,通過反射可以得到*.exe或*.dll等程式集內部的介面、類、方法、欄位、屬性、特性等資訊,還可以動態創建出型別例項並執行其中的方法。
反射的功能很強大,任何複雜抽象的分層架構或者複雜的設計模式均是建立在這些基礎之上的,比如我們要進行模組化、元件化開發,要嚴格的消除模組之間的耦合,要進行動態介面呼叫。開發這樣強大而靈活的系統,必須要用反射才行,我們只要把它用在合適的位置,不僅能使程式碼變的清晰簡潔,更能讓它發揮出驚人的力量。

反射的用途

型別 作用
Assembly 定義和載入程式集,載入程式集清單中列出的模組,以及從此程式集中查詢型別並建立該型別的例項。
Module 瞭解包含模組的程式集以及模組中的類等,還可以獲取在模組上定義的所有全域性方法或其他特定的非全域性方法。
ConstructorInfo 瞭解構造器的名稱、引數、訪問修飾符(如public或private)和實現詳細資訊(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法來呼叫特定的建構函式。
MethodInfo 瞭解方法的名稱、返回型別、引數、訪問修飾符(如public或private)和實現詳細資訊(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法來呼叫特定的方法。
FieldInfo 瞭解欄位的名稱、訪問修飾符(如public或private)和實現詳細資訊(如static)等,並獲取或設定欄位值。
EventInfo 瞭解事件的名稱、事件處理程式資料型別、自定義特性、宣告型別和反射型別等,並新增或移除事件處理程式。
PropertyInfo 瞭解屬性的名稱、資料型別、宣告型別、反射型別和只讀或可寫狀態等,並獲取或設定屬性值。
ParameterInfo 瞭解引數的名稱、資料型別、引數是輸入引數還是輸出引數等,以及引數在方法簽名中的位置等。

System.Type類

System.Type類對於反射有很重要的作用。它是一個抽象的基類,Type有與每種資料型別對應的派生類,我們使用這個派生類的物件的方法、欄位、屬性來查詢有關該型別的所有資訊。
獲取給定型別的Type值有三種常用方式:

  • 使用C# typeof運算子
    Type t=typeof(string);
  • 使用物件的GetType()方法
    string s=”guo”;Type t=s.GetType();
  • 呼叫Type類的靜態方法GetType()
    Type t=Type.GetType(“System.String”);

獲取程式集資訊

namespace ReflectionTest
{
    class ReflectionHelper
    {
        public void GetAssemblyInfo()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            Console.WriteLine("程式集全名:{0}", assembly.FullName);
            Console.WriteLine("程式集的版本:{0}", assembly.GetName().Version);
            Console.WriteLine("程式集初始位置:{0}", assembly.CodeBase);
            Console.WriteLine("程式集位置:{0}", assembly.Location);
            Console.WriteLine("程式集入口:{0}", assembly.EntryPoint);
            Type[] types = assembly.GetTypes();
            Console.WriteLine("程式集中包含的型別:");
            foreach (Type item in types)
            {
                Console.WriteLine("類:" + item.Name);
            }
        }
    }
}

這裡寫圖片描述

獲取型別資訊

namespace ReflectionTest
{
    class ReflectionHelper
    {
        public void GetTypeInfo()
        {
            Type type = typeof(Person);
            Console.WriteLine("型別名:{0}", type.Name);
            Console.WriteLine("類全名:{0}", type.FullName);
            Console.WriteLine("名稱空間:{0}", type.Namespace);
            Console.WriteLine("程式集名:{0}", type.Assembly);
            Console.WriteLine("模組名:{0}", type.Module);
            Console.WriteLine("基類名:{0}", type.BaseType);
            Console.WriteLine("是否類:{0}", type.IsClass);
            Console.WriteLine("類的公共成員:");
            MemberInfo[] members = type.GetMembers();
            foreach (MemberInfo memberInfo in members)
            {
                Console.WriteLine("{0}:{1}", memberInfo.MemberType, memberInfo);
            }
        }
    }
}

這裡寫圖片描述

反射呼叫方法

namespace ReflectionTest
{
    class ReflectionHelper
    {
        public void InvokeMethod()
        {
            #region 方法一
            Assembly assembly1 = Assembly.Load("ReflectionTest");
            Type type1 = assembly1.GetType("ReflectionTest.Person");
            object obj1 = System.Activator.CreateInstance(type1);
            MethodInfo method1 = type1.GetMethod("Show");
            method1.Invoke(obj1, null);
            #endregion

            #region 方法二
            object obj2 = Assembly.Load("ReflectionTest").CreateInstance("ReflectionTest.Person");
            Type type2 = obj2.GetType();
            MethodInfo method = type2.GetMethod("Show");
            method.Invoke(obj2, null);
            #endregion
        }
    }
}

反射實現工廠模式

namespace ReflectionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //方法一
            AbsFruit absFruit = FruitFactory.CreateInstance<AbsFruit>("ReflectionTest", "Strawberry");
            absFruit.Show();
            //方法二
            //string fullTypeName = typeof (Strawberry).FullName;
            string fullTypeName = typeof (Strawberry).AssemblyQualifiedName;            
            AbsFruit absFruit2 = FruitFactory.CreateInstance<AbsFruit>(fullTypeName);
            absFruit2.Show();
        }
    }
}
namespace ReflectionTest
{
    public class FruitFactory
    {
        public static T CreateInstance<T>(string nameSpace,string className)
        {
            string fullClassName = nameSpace + "." + className;
            return (T)Assembly.Load(nameSpace).CreateInstance(fullClassName);
        }

        public static T CreateInstance<T>(string fullTypeName)
        {
            return (T)Activator.CreateInstance(Type.GetType(fullTypeName));
        }
    }
}
public abstract class AbsFruit
{
    protected string Name { get; set; }
    public abstract void Show();
}
class Strawberry:AbsFruit
{
    public Strawberry()
    {
        Name = "草莓";
    }
    public override void Show()
    {
        Console.WriteLine("水果型別:" + Name);
    }
}