学更好的别人,
做更好的自己。
——《微卡智享》

本文长度为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
完

扫描二维码
获取更多精彩
微卡智享

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

被折叠的 条评论
为什么被折叠?



