最近用到的反射比较多。在此总结和记录。
一、反射获取DLL信息
/// <summary> /// 获取Dll的名称 /// </summary> /// <param name="dllpath"></param> /// <returns></returns> public bool GetDLLName(string dllPath, out string dllName, out string dllGuid) { dllName = null; dllGuid = null; //可以注册使用了,其实此处的注册就是在树上加一个节点,然后把这个新的树反序列化到文件中 //增加一个节点,此处必须知道这个工具叫什么名字了,还是需要看看这个东西 Assembly assembly = Assembly.LoadFile(dllPath); //this.DebugLog("正在加载插件。。。"); // 获取当前dll中的所有的public类型 Type[] types = assembly.GetExportedTypes(); Type typeUserControl = typeof(UserControl); int countUserControl = 0; Type typePlugin = null; foreach (Type type in types) { //验证当前的类型UserControl的类 if (typeUserControl.IsAssignableFrom(type) && type.IsClass) { typePlugin = type; countUserControl++; } } if (countUserControl > 1) { //DevMessageBoxUtil.Info("被注册的dll插件中的公共类型多余1个\n请修改插件,使其公共类型个数为1。"); throw new PluginCreatingException(ConstInfo.EXCEPTION_MSG_OVER_MUCH_PLUGIN); //return false; } else if (countUserControl < 1) { //DevMessageBoxUtil.Info("没有发现可被注册的插件"); //return false; throw new PluginCreatingException(ConstInfo.EXCEPTION_MSG_PLUGIN_NOT_FOUND); } object plugin = Activator.CreateInstance(typePlugin); UserControl uc = plugin as UserControl; if (uc == null) { //DevMessageBoxUtil.Info("此插件不继承UserControl类"); //return false; throw new PluginCreatingException(ConstInfo.EXCEPTION_MSG_PLUGIN_NOT_USERCONTROL); } // 向当前树节点添加一个子节点 GeneralToolModel genTool = new GeneralToolModel(); IEnumerator<CustomAttributeData> enumerator = assembly.CustomAttributes.GetEnumerator(); enumerator.Reset(); CustomAttributeData attrName = null; CustomAttributeData attrGuid = null; while (enumerator.MoveNext()) { CustomAttributeData attrCurrent = enumerator.Current; if (attrCurrent.AttributeType == typeof(AssemblyTitleAttribute)) { attrName = attrCurrent; } if (attrCurrent.AttributeType == typeof(GuidAttribute)) { attrGuid = attrCurrent; } } if (attrName == null || attrGuid == null) { //DevMessageBoxUtil.Info("插件描述信息AssemblyInfo内容缺失,请修改插件"); //return false; throw new PluginCreatingException(ConstInfo.EXCEPTION_MSG_PLUGIN_ASSEMBLY_INFO_NOT_DEFINED); } dllName = attrName.ConstructorArguments[0].Value.ToString(); dllGuid = attrGuid.ConstructorArguments[0].Value.ToString(); return true; } |
二、使用程序域获取DLL的概要信息,不会占用DLL,可以在不使用DLL的情况下热删除
1.RemoteLoader类
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace XXX { /// <summary> /// 目的:远程加载程序集,获取程序集中的可序列号信息或者执行方法 /// 主程序域和子程序域直接无法传递不可序列化的对象,确认一下UC是否是可序列化的 /// 创建人:王杰 /// 创建日期:2018-08-24 /// 修改描述:程序域和Dev的SplashScreenManager进度条冲突:程序域处理时间过长,静态的SplashScreenManager成为null,猜想可能被垃圾回收器回收了 /// 处理结果:GetDLLName方法放置在了PluginService中 /// 修改人:王杰 /// 修改日期:2018-10-20 /// 备注: /// </summary> public class RemoteLoader : MarshalByRefObject { #region uc无法穿越AppDomain边界,所以dll被使用后,必须重启 //public UserControl GetUC(string dllpath) //{ // Assembly assembly = Assembly.LoadFile(dllpath); // //this.DebugLog("正在加载插件。。。"); // // 获取当前dll中的所有的public类型 // Type[] types = assembly.GetExportedTypes(); // Type typeUserControl = typeof(UserControl); // int countUserControl = 0; // Type typePlugin = null; // foreach (Type type in types) // { // //验证当前的类型UserControl的类 // if (typeUserControl.IsAssignableFrom(type) && type.IsClass) // { // typePlugin = type; // countUserControl++; // } // } // if (countUserControl > 1) // { // DevMessageBoxUtil.Info("被注册的dll插件中的公共类型多余1个\n请修改插件,使其公共类型个数为1。"); // return null; // } // else if (countUserControl < 1) // { // DevMessageBoxUtil.Info("没有发现可被注册的插件"); // return null; // } // object plugin = Activator.CreateInstance(typePlugin); // UserControl uc = plugin as UserControl; // if (uc == null) // { // DevMessageBoxUtil.Info("此插件不继承UserControl类"); // return null; // } // return uc; //} #endregion /// <summary> /// 获取Dll的名称 /// </summary> /// <param name="dllpath"></param> /// <returns></returns> public bool GetDLLName(string dllPath, out string dllName, out string dllGuid) { //...同上GetDLLName } } } |
2.使用RemoteLoader类
string callingDomainName = AppDomain.CurrentDomain.FriendlyName;//Thread.GetDomain().FriendlyName; //this.DebugLog(callingDomainName);AppDomain ad = AppDomain.CreateDomain("RemoteLoadePlugin"); //Assembly ass = Assembly.GetExecutingAssembly(); string currentAssembly = Assembly.GetExecutingAssembly().Location; RemoteLoader loader = (RemoteLoader)ad.CreateInstanceFromAndUnwrap(currentAssembly, typeof(RemoteLoader).ToString()); |
三、使用反射订阅事件
1.订阅
/// <summary> /// 通过反射给订阅者注册事件/// </summary> /// <param name="publisher">发布者对象</param> /// <param name="subscriber">订阅者对象</param> /// <param name="EventName">订阅事件名称</param> /// <param name="CallbackName">事件的回调函数,此处必须为订阅者的实例函数</param> private void RegisterEvent(object publisher, object subscriber, string EventName, string CallbackName) { Type t = publisher.GetType(); EventInfo eventInfo = t.GetEvent(EventName); if (eventInfo != null) { Type eventHanderType = eventInfo.EventHandlerType; Type tThis = subscriber.GetType(); BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; MethodInfo methodCallback = tThis.GetMethod(CallbackName, myBindingFlags); //回调函数有静态函数和实例函数的区别,如果不设置第二个参数或为null,则表示为静态函数,就会出现this为null的情况 Delegate del = Delegate.CreateDelegate(eventHanderType, subscriber, methodCallback); eventInfo.AddEventHandler(publisher, del); } } |
2.使用
void UCProfessionalTool_Load(object sender, EventArgs e) { this._service.DisplayProfessionalTool(this.tabMain, this._professionalTool, this._plugins); //注册每个插件的完成事件 foreach (string key in this._plugins.Keys) { UserControl uc = this._plugins[key]; //Type t = uc.GetType(); //EventInfo eventInfo = t.GetEvent(PluginInfo.PLUGIN_EVENT_WORK_FINISHED); //if (eventInfo != null) //{ // Type eventHanderType = eventInfo.EventHandlerType; // Type tThis = this.GetType(); // BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; // MethodInfo methodCallback = tThis.GetMethod(PluginInfo.PLUGIN_CALLBACK_WORK_FINISHED, myBindingFlags); // //回调函数有静态函数和实例函数的区别,如果不设置第二个参数或为null,则表示为静态函数,就会出现this为null的情况 // Delegate del = Delegate.CreateDelegate(eventHanderType, this, methodCallback); // eventInfo.AddEventHandler(uc, del); //} this.RegisterEvent(uc, this, PluginInfo.PLUGIN_EVENT_WORK_FINISHED, PluginInfo.PLUGIN_CALLBACK_WORK_FINISHED); this.RegisterEvent(uc, this, PluginInfo.PLUGIN_EVENT_WORK_FLOW_FINISHED, PluginInfo.PLUGIN_CALLBACK_WORK_FLOW_FINISHED); } } |