根據字符串調用同名函數

需求:

在工作中遇到某一部分代碼是通過另一款軟件導出來的,在實際的項目部署中,這部分代碼會經常變動,那麼類名和函數名就會不確定,在覈心代碼部分就很難靈活應對。於是,利用C#的反射方法,實現了一個dll封裝,可以把要執行的方法放到配置文件裏,實現動態調用。

具體實現:

代碼封裝

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace DllDynamicCall
{
    public class DllCall
    {
        private Assembly _assembly;

        public Dictionary<string,object> Objects { get; set; }

        public Dictionary<string,Dictionary<string,MethodInfo>> Methods { get; set; }

        /// <summary>
        /// 構造器
        /// </summary>
        /// <param name="dllPath">DLL絕對路徑</param>
        public DllCall(string dllPath)
        {
           LoadDll(dllPath);

            Objects=new Dictionary<string, object>();
            Methods =new Dictionary<string, Dictionary<string, MethodInfo>>();
        }

        #region 公開方法

        /// <summary>
        /// 註冊要目標類
        /// </summary>
        /// <param name="classFullName">類的完全限定名</param>
        /// <param name="objectName">指定的對象名</param>
        /// <param name="constructorParaTypes">構造器參數類型</param>
        /// <param name="constructorParas">構造器參數</param>
        public void RegisterObject(string classFullName,string objectName, Type[] constructorParaTypes,object[] constructorParas)
        {
            Type t = _assembly.GetType(classFullName, true, false);

            ConstructorInfo constructorInfo = t.GetConstructor(constructorParaTypes);

            if (constructorInfo != null)
            {
                object targetObject = constructorInfo.Invoke(constructorParas);

                if (!Objects.ContainsKey(objectName))
                {
                    Objects.Add(objectName,targetObject);
                }
                if (!Methods.ContainsKey(objectName))
                {
                    Methods.Add(objectName, new Dictionary<string, MethodInfo>());
                }
            }
        }

        /// <summary>
        /// 註冊函數
        /// </summary>
        /// <param name="classFullName">類完全限定名</param>
        /// <param name="objectName">制定函數所在對象名</param>
        /// <param name="funcName">函數名</param>
        public void RegisterFunc(string classFullName, string objectName,string funcName)
        {
            Type t = _assembly.GetType(classFullName, true, false);
            MethodInfo method = t.GetMethod(funcName);
            if (Methods.ContainsKey(objectName))
            {
                if (!Methods[objectName].ContainsKey(funcName))
                {
                    Methods[objectName].Add(funcName,method);
                }
            }
        }

        /// <summary>
        /// 調用函數
        /// </summary>
        /// <param name="objectName">目標對象名</param>
        /// <param name="funcName">函數名</param>
        /// <param name="paras">參數表,沒有參數則用null</param>
        /// <returns></returns>
        public object CallFunc(string objectName, string funcName, object[] paras)
        {
            Dictionary<string,MethodInfo> targetObjec = Methods[objectName];
            MethodInfo targetFunc = targetObjec[funcName];
            var flag = BindingFlags.Public | BindingFlags.Instance;
            object result = targetFunc. Invoke(Objects[objectName],flag,Type.DefaultBinder, paras,null);
            return result;
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 加載DLL
        /// </summary>
        /// <param name="dllPath">DLL絕對路徑</param>
        private void LoadDll(string dllPath)
        {
            if (File.Exists(dllPath))
            {
                _assembly = Assembly.LoadFrom(dllPath);
            }
            else
            {
                throw new FileNotFoundException($"{dllPath} isn't exist!");
            }

        }

        #endregion
    }
}

要調用的對象DLL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestDll
{
    public class Person
    {
        private readonly int _a;
        private readonly string _b;

        public Person()
        {

        }

        public Person(string racial,int weight)
        {
            this._a = weight;
            this._b = racial;
        }

        public string ShowMessage(string name,int age)
        {
            return name + " is " + age + " years old.";
        }

        public string ShowFeature()
        {
            return _a + "  " + _b;
        }
    }
}

測試代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            // 根據絕對路徑加載DLL
            var dyDll = new DllDynamicCall.DllCall(@"E:\C#\UsageOfReflection\Test\bin\Debug\TestDll.dll");
            // 註冊類實例
            dyDll.RegisterObject("TestDll.Person", "goodMan", new Type[] { typeof(string), typeof(int) }, new object[] { "亞洲", 180 });
            // 註冊特定實例的實例方法(命名空間TestDll,類Person,實例goodMan,方法ShowMessage)
            dyDll.RegisterFunc("TestDll.Person", "goodMan", "ShowMessage");
            // 註冊特定實例的實例方法(命名空間TestDll,類Person,實例goodMan,ShowFeature)
            dyDll.RegisterFunc("TestDll.Person", "goodMan", "ShowFeature");

            // 調用方法
            var message1 = (string)dyDll.CallFunc("goodMan", "ShowMessage", new object[] { "張三", 45 });
            var message2 = (string)dyDll.CallFunc("goodMan", "ShowFeature", null);

            Console.WriteLine(message1);
            Console.WriteLine(message2);
            Console.ReadKey();
        }
    }
}

源代碼

源代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章