进阶|C#利用反射方式动态调用类库里的方法(附源码)

本文详细介绍如何使用反射动态调用类库中的方法,包括获取并加载类库、获取类和方法信息,以及实例化对象和调用方法的具体步骤。同时,提供了检测当前系统.NET Framework版本的方法。

学更好的别人,

做更好的自己。

——《微卡智享》

本文长度为1999,预计阅读5分钟


前言

做为2020年第一篇技术文章,我们就直接分享一个进阶的的东西,利用反射方式动态调用类库执行方法。

这个Demo里除了有利用反射动态调用类库方法,还有一个是检测当前系统安装的.netframework的版本方法,算是给大家的福利。

反射的作用

1.  将类型绑定到现有对象,或从现有对象中获取类型信息,这些信息包括(Assembly   MemberInfo  EventInfo  FieldInfo  MethodBase  ConstructorInfo  MethodInfo  PropertyInfo 等等 )另外可以使用反射动态地创建类型的实例,

2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。

3.  

反射主要应用类库,这些类库需要知道一个类型的定义,以便提供更多的功能。

4. 

反射能够调用一些私有方法和字段等

本章由来

写这篇的原因其实就是上面我们说到的反射作用的场景第二条,还是我自己做的那个商盘通的程序,后端用的.netframework4.0的框架,以前连接数据库都是自己封装好的,前阵子不是我们学习过sqlsugar的orm框架,在项目中用到的觉得挺不错的,所以就想移植过来,不过sqlsugar要求的.netframework4.5的框架,如果我们把整个项目都要升级到.netfrmework4.5,只装了4.0的用户打开程序肯定会报错,影响用户体验,于是我就自己想了一个思路,把sqlsugar相关的所有操作都封装好一个类库里,然后通过判断用户的.netframework的版本,来实现是否自动调用新的这个类库,思路如下:

嗯,由上面的思路看,完美,然后就开始做相关的Demo,结果很快写完后测试立马被啪啪的打脸,发现低版本框架的程序不能调用高版本的类库,也就是说我的主程序一直用的.netframework4.0,不能调用为.netframework4.5的类库,所以这个方案就被否决了,不过最终不能用上,不代表没有价值,反射调用类库的方法还是要学习的,而且我也把它调用成功的封装了一个单元文件,直接引用即可。

核心代码

微卡智享

下面是先初始化要加载的类库方法

//获取并加载DLL类库中的程序集
ass = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "\\" + this.strDllName + ".dll");

//获取类的类型:必须使用名称空间+类名称
type = ass.GetType(this.strDllName + "." + this.strClsName);

//获取类的方法:方法名称
method = type.GetMethod(this.strMetName);

调用类库中的方法

//对获取的类进行创建实例。//必须使用名称空间+类名称
obj = ass.CreateInstance(this.strDllName + "." + this.strClsName);

//开始搜索方法
method = type.GetMethod(this.strMetName);

//调用方法
method.Invoke(obj, object[]);

调用类库中的静态方法

//开始搜索方法
method = type.GetMethod(this.strMetName);

//静态方法第一个参数直接传递null
method.Invoke(null, object[]);

代码演示

微卡智享

我们新建一个了项目名称为NetFrameWorkDemo,然后再添加一个类库名称为LibDotNet45,先在LibDotNet45的类库中写实现的方法

LibDotNet45

在LibDotNet45的类库中,我们加入一个Test.cs的文件,里面写了四个方法,其中有一个为静态方法,如下图:

检测.NetFrameWork版本

项目中DotNetApi.cs即是可以检测.netframework的版本,里面的GetDotNetVersion的方法就是检测方法,直接上代码:

/// <summary>
        /// 判断.Net Framework的Version是否符合需要
        /// (.Net Framework 版本在2.0及以上)
        /// </summary>
        /// <param name="version">需要的版本 version = 4.5</param>
        /// <param name="sysversion">输出的系统当前的DOTNET版本号</param>
        /// <returns></returns>
        public static bool GetDotNetVersion(string version, ref string sysversion)
        {
            string oldname = "0";
            using (RegistryKey ndpKey =
                RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
                OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
            {
                foreach (string versionKeyName in ndpKey.GetSubKeyNames())
                {
                    if (versionKeyName.StartsWith("v"))
                    {
                        RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                        string newname = (string)versionKey.GetValue("Version", "");
                        if (string.Compare(newname, oldname) > 0)
                        {
                            oldname = newname;
                        }
                        if (newname != "")
                        {
                            continue;
                        }
                        foreach (string subKeyName in versionKey.GetSubKeyNames())
                        {
                            RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                            newname = (string)subKey.GetValue("Version", "");
                            if (string.Compare(newname, oldname) > 0)
                            {
                                oldname = newname;
                            }
                        }
                    }
                }
            }
            sysversion = oldname;
            return string.Compare(oldname, version) > 0 ? true : false;
        }

封装好的反射调用方法类

DynamicCallLib是们封装好的调用反射类,调用的方法按有没有返回值分为2种,按是否静态调用分为2种,所以一共有4种方法。

其中带返回参数的我们用泛型处理,这样可以通用,具体的整个类的代码如下:

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

namespace NetFrameworkCheckDemo
{
    /// <summary>
    /// 动态库调类库方法
    /// 反射类
    /// 利用反射动态调用DLL类库。
    /// </summary>
    public class DynamicCallLib
    {
        //调用的库名
        private string strDllName = "";
        //调用的类名
        private string strClsName = "";
        //调用的方法
        private string strMetName = "";

        //判断初始化是否成功
        public bool isinit = false;

        //反射调用的参数
        private Assembly ass;
        private Type type;
        private MethodInfo method;
        private object obj;


        public DynamicCallLib(string Dllname, string ClsName, string MetName)
        {
            strDllName = Dllname;
            strClsName = ClsName;
            strMetName = MetName;
            InitReflection();
        }

        /// <summary>
        /// 初始化返射
        /// </summary>
        public void InitReflection()
        {
            if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\" + strDllName + ".dll"))
            {
                //获取并加载DLL类库中的程序集
                ass = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "\\" + this.strDllName + ".dll");
                //获取类的类型:必须使用名称空间+类名称
                type = ass.GetType(this.strDllName + "." + this.strClsName);
                //获取类的方法:方法名称
                method = type.GetMethod(this.strMetName);
                isinit = true;
            }
            else
            {
                isinit = false;
            }
        }

        /// <summary>
        /// 调用没有返回值的方法
        /// </summary>
        /// <param name="objparams">输入的参数集合</param>
        /// <param name=""></param>
        public void CallvoidMethod(object[] objparams = null)
        {
            if (!isinit) throw new Exception("类库初始化失败,无法调用方法!");
            //对获取的类进行创建实例。//必须使用名称空间+类名称
            obj = ass.CreateInstance(this.strDllName + "." + this.strClsName);
            //开始搜索方法
            method = type.GetMethod(this.strMetName);

            //调用方法
            method.Invoke(obj, objparams);
        }

        /// <summary>
        /// 调用静态方法
        /// </summary>
        /// <param name="objparams"></param>
        public void StaticCallvoidMethod(object[] objparams = null)
        {
            if (!isinit) throw new Exception("类库初始化失败,无法调用方法!");
            //开始搜索方法
            method = type.GetMethod(this.strMetName);
            //静态方法第一个参数直接传null
            method.Invoke(null, objparams);
        }

        /// <summary>
        /// 调用带返回值的方法
        /// </summary>
        /// <param name="objparams"></param>
        /// <returns></returns>
        public T CallResMethod<T>(object[] objparams = null)
        {
            if (!isinit) throw new Exception("类库初始化失败,无法调用方法!");
            T t = default(T);
            //对获取的类进行创建实例。//必须使用名称空间+类名称
            obj = ass.CreateInstance(this.strDllName + "." + this.strClsName);
            //开始搜索方法
            method = type.GetMethod(this.strMetName);

            //调用方法
            t = (T)method.Invoke(obj, objparams);

            return t;
        }

        /// <summary>
        /// 调用静态返回值的方法
        /// </summary>
        /// <param name="objparams"></param>
        /// <returns></returns>
        public T StaticCallResMethod<T>(object[] objparams = null)
        {
            if (!isinit) throw new Exception("类库初始化失败,无法调用方法!");
            T t = default(T);
            //开始搜索方法
            method = type.GetMethod(this.strMetName);
            //调用方法
            t = (T)method.Invoke(null, objparams);

            return t;
        }

    }
}

调用方法

微卡智享

调用静态方法

private void btntest1_Click(object sender, EventArgs e)
        {
            try
            {
                DynamicCallLib callLib = new DynamicCallLib("LibDotNet45", "Test", "getstring");
                string resstr = callLib.StaticCallResMethod<string>(new object[] { "我来试试" });
                tbMsg.AppendText(resstr + "\r\n");
            }
            catch (Exception ex)
            {
                tbMsg.AppendText(ex.Message + "\r\n");
            }
        }

调用Void方法

private void btntest2_Click(object sender, EventArgs e)
        {
            try
            {
                DynamicCallLib callLib = new DynamicCallLib("LibDotNet45", "Test", "readint");
                callLib.CallvoidMethod(new object[] { 76 });
            }
            catch (Exception ex)
            {
                tbMsg.AppendText(ex.Message + "\r\n");
            }
        }

调用无参数方法

private void btntest3_Click(object sender, EventArgs e)
        {
            try
            {
                DynamicCallLib callLib = new DynamicCallLib("LibDotNet45", "Test", "getint");
                int qty = callLib.CallResMethod<int>();
                tbMsg.AppendText("得到的返回数为" + qty + "\r\n");
            }
            catch (Exception ex)
            {
                tbMsg.AppendText(ex.Message + "\r\n");
            }
        }

调用多参数方法

private void btntest4_Click(object sender, EventArgs e)
        {
            try
            {
                DynamicCallLib callLib = new DynamicCallLib("LibDotNet45", "Test", "resstring");
                string res = callLib.CallResMethod<string>(new object[] { "今天赚了多少钱?", 25.43f });
                tbMsg.AppendText("返回消息:" + res + "\r\n");
            }
            catch (Exception ex)
            {
                tbMsg.AppendText(ex.Message + "\r\n");
            }
        }

Demo地址

https://github.com/Vaccae/DynamicCallLib.git

扫描二维码

获取更多精彩

微卡智享

「 往期文章 」

回顾|我的2019

学习|Android中两个PhotoView对比及Glide的扩展使用

学习|Android播放网络视频综合运用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vaccae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值