根据字符串调用同名函数

需求:

在工作中遇到某一部分代码是通过另一款软件导出来的,在实际的项目部署中,这部分代码会经常变动,那么类名和函数名就会不确定,在核心代码部分就很难灵活应对。于是,利用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();
        }
    }
}

源代码

源代码

posted on 2017-09-23 09:55  五月槐花  阅读(617)  评论(0编辑  收藏  举报

导航