首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 反射技術封裝:Invoker 工具類完整實作

     編輯:關於.NET

前言

若有人詢問如何呼叫類別的 private 方法或存取私有成員,不懂反射者會回答「不能」。但有了反射,一切皆有可能。雖然反射會破壞封裝性,但在特定情境下(如無法修改源碼的第三方 DLL 中類別被標記為 internal)極為實用。本文提供一個封裝常用反射操作的 Invoker 類別,代碼簡潔無註解,開箱即用。

Invoker 類別完整代碼

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace UsefulUtility
{
    public class Invoker
    {
        private static BindingFlags flags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase;

        // 取得類型
        public static Type GetType(Assembly asm, string typeFullName) => asm.GetType(typeFullName);

        public static Type GetInnerType(string hiddenTypeName, Type outerType) => outerType.Module.GetType(hiddenTypeName);

        // 取得方法資訊
        public static MethodInfo GetMethod(Type type, string funcName, Type[] paramTypes)
            => paramTypes != null ? type.GetMethod(funcName, flags, null, paramTypes, null) : type.GetMethod(funcName, flags);

        public static MethodInfo GetMethod(Type type, string funcName) => GetMethod(type, funcName, null);

        // 呼叫實例方法
        public static object CallMethod(object obj, string funcName, params object[] parameters)
        {
            Type type = obj.GetType();
            MethodInfo method = GetMethod(type, funcName, GetTypesFromObjects(parameters));
            return method.Invoke(obj, parameters);
        }

        // 呼叫靜態方法
        public static object CallStaticMethod(Type type, string funcName, params object[] parameters)
        {
            MethodInfo method = GetMethod(type, funcName, GetTypesFromObjects(parameters));
            return method.Invoke(null, parameters);
        }

        // 取得/設定實例屬性
        public static object GetProperty(object obj, string propertyName) => GetProperty(obj, propertyName, null);
        public static object GetProperty(object obj, string propertyName, params object[] index)
        {
            Type type = obj.GetType();
            return type.GetProperty(propertyName, flags).GetValue(obj, index);
        }

        public static void SetProperty(object obj, string propertyName, object value) => SetProperty(obj, propertyName, value, null);
        public static void SetProperty(object obj, string propertyName, object value, params object[] index)
        {
            Type type = obj.GetType();
            type.GetProperty(propertyName, flags).SetValue(obj, value, index);
        }

        // 取得/設定靜態屬性
        public static object GetStaticProperty(Type type, string propertyName) => GetStaticProperty(type, propertyName, null);
        public static object GetStaticProperty(Type type, string propertyName, params object[] index)
            => type.GetProperty(propertyName, flags).GetValue(null, index);

        public static void SetStaticProperty(Type type, string propertyName, object value) => SetStaticProperty(type, propertyName, value, null);
        public static void SetStaticProperty(Type type, string propertyName, object value, params object[] index)
            => type.GetProperty(propertyName, flags).SetValue(null, value, index);

        // 取得/設定實例欄位
        public static object GetField(object obj, string fieldName)
        {
            Type type = obj.GetType();
            return type.GetField(fieldName, flags).GetValue(obj);
        }

        public static object GetSaticField(Type type, string fieldName)
            => type.GetField(fieldName, flags).GetValue(null);

        public static void SetField(object obj, string fieldName, object value)
        {
            Type type = obj.GetType();
            type.GetField(fieldName, flags).SetValue(obj, value);
        }

        public static void SetStaticField(Type type, string fieldName, object value)
            => type.GetField(fieldName, flags).SetValue(null, value);

        // 建立實例
        private static ConstructorInfo GetConstructor(Type type, Type[] paramTypes) => type.GetConstructor(paramTypes);

        public static object CreateInstance(Type type, Type[] paramTypes, params object[] parameters)
            => GetConstructor(type, paramTypes).Invoke(parameters);

        public static object CreateInstance(Type type, params object[] parameters)
            => GetConstructor(type, GetTypesFromObjects(parameters)).Invoke(parameters);

        private static Type[] GetTypesFromObjects(object[] objs)
        {
            Type[] types = new Type[objs.Length];
            for (int i = 0; i < types.Length; i++) types[i] = objs[i].GetType();
            return types;
        }

        // 事件處理
        public static void AddEventHandler(object obj, string eventName, MethodInfo method, object methodOwner)
        {
            EventInfo eventInfo = obj.GetType().GetEvent(eventName, flags);
            Delegate eventDeleg = Delegate.CreateDelegate(eventInfo.EventHandlerType, methodOwner, method);
            eventInfo.AddEventHandler(obj, eventDeleg);
        }

        public static void RemoveEventHandler(object obj, string eventName, MethodInfo method, object methodOwner)
        {
            EventInfo eventInfo = obj.GetType().GetEvent(eventName, flags);
            Delegate eventDeleg = Delegate.CreateDelegate(eventInfo.EventHandlerType, methodOwner, method);
            eventInfo.RemoveEventHandler(obj, eventDeleg);
        }
    }
}

實戰測試:操作 Fetion SDK DLL

以下示範載入 Fetion SDK.dll,透過反射實例化 SDK、設定帳號、訂閱事件、呼叫登入方法,登入成功後發送測試簡訊:

using System;
using System.Collections.Generic;
using System.Text;
using UsefulUtility;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static object sdk;
        static Assembly asm;

        [STAThread]
        static void Main(string[] args)
        {
            // 載入組件
            asm = Assembly.LoadFrom("Fetion SDK.dll");
            // 取得 SDK 類型
            Type type = Invoker.GetType(asm, "com.hetaoos.FetionSDK.FetionSDK");
            // 實例化
            sdk = Invoker.CreateInstance(type);
            // 取得帳號管理屬性
            object accountManager = Invoker.GetProperty(sdk, "AccountManager");
            // 設定用戶名密碼
            Invoker.CallMethod(accountManager, "FillUserIdAndPassword", new object[] { "手機號碼", "飛信密碼", false });
            // 訂閱狀態變更事件
            Invoker.AddEventHandler(sdk, "SDK_UserSatusChange", Invoker.GetMethod(typeof(Program), "sdk_SDK_UserSatusChange"), null);
            // 呼叫登入
            Invoker.CallMethod(accountManager, "Login");
        }

        static void sdk_SDK_UserSatusChange(object sender, EventArgs e)
        {
            Console.WriteLine(Invoker.GetProperty(e, "NewStatus"));
            Console.WriteLine(Invoker.GetSaticField(Invoker.GetType(asm, "Imps.Client.UserAccountStatus"), "Logon"));

            if (Invoker.GetProperty(e, "NewStatus").Equals(Invoker.GetSaticField(Invoker.GetType(asm, "Imps.Client.UserAccountStatus"), "Logon")))
            {
                Console.WriteLine("hello");
                object contactControl = Invoker.GetProperty(sdk, "ContactControl");
                object sendSMS = Invoker.GetProperty(contactControl, "SendSMS");
                Invoker.CallMethod(sendSMS, "SendSMS", "要發送信息的飛信號或手機號碼", "hello, a test");
            }
        }
    }
}

原文出處:https://www.cnblogs.com/dlutwy/archive/2009/04/28/1445352.html

結語

Invoker 封裝了反射的高頻操作:型別獲取、方法調用、屬性/欄位存取、實例建立、事件綁定。在無法直接引用類別或需動態操作未知型別時,它能大幅簡化代碼。但請謹記:反射會破壞封裝、影響效能且繞過編譯期檢查,僅在必要時使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved