cad提供的 IExtensionApplication 接口 是不能实现一次以上的,那么这给编写代码带来了一种不好的情况是,每次都要去修改实现这个接口的类,
如果是一个小的测试功能,你又要去动前面的核心,这样就感觉很蛋疼....编程思维上面叫做"开闭原则":对拓展进行开放,对修改进行关闭.
所以我是这么想的,在实现IExtensionApplication接口的 Initialize 和 Terminate 时候,
用反射来找到某个接口(仿IExtensionApplication接口的),然后搜下面接口的 Initialize 和 Terminate,然后运行这个它.
20191227增加了控制加载顺序的函数
仿IExtensionApplication接口的接口.
/// <summary> /// 控制加载顺序 /// </summary> public enum Sequence : byte { First,// 最先 Last, // 最后 } public interface IAutoGo { // 控制加载顺序 Sequence SequenceId(); // 关闭cad的时候会自动执行 void Terminate(); //打开cad的时候会自动执行 void Initialize(); }
继承 IExtensionApplication 接口的函数,cad加载这个dll,就会运行它.
class RunClass { Type _ty; public string NamePace { get; private set; } public string ClassName { get; private set; } public Sequence SequenceId { get { Sequence sequence = Sequence.Last; try { string sequenceId = "SequenceId"; _ty = Assembly.Load(NamePace).GetType(ClassName); //加载命名空间下的class MethodInfo method = _ty.GetMethod(sequenceId); //获取这个class的方法 //居然是静态获取返回的枚举值 object instanceObject = Activator.CreateInstance(_ty); object returnValue1 = method.Invoke(instanceObject, null); //运行 sequence = (Sequence)returnValue1; } catch { } return sequence; } } public RunClass(string namePace, string className) { NamePace = namePace; ClassName = className; } public void Run(string methodInfoName) { try { MethodInfo method = _ty.GetMethod(methodInfoName); //获取这个class的方法 if (method.IsStatic)//判断是否静态方法 { method.Invoke(null, null);//静态调用 } else //非静态,调用实例化方法 { object instanceObject = Activator.CreateInstance(_ty); object returnValue1 = method.Invoke(instanceObject, null); //运行 } } catch (System.Exception) { throw; } } } //为了解决IExtensionApplication在一个dll内无法多次实现接口的关系 //所以在这里反射加载所有的IAutoGo,以达到能分开写"启动运行"函数的目的 public class AutoClass : IExtensionApplication { //打开cad的时候会自动执行 public void Initialize() { RunIAutoGo("Initialize"); } //关闭cad的时候会自动执行 public void Terminate() { //可以用 //MessageBox.Show("哇哇哇哇哇"); //不可以用,此时的cad界面都已经关闭了...涉及内存释放的问题 //Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; RunIAutoGo("Terminate"); } // 通过反射获取所有继承了IAutoGo接口的类! // https://www.cnblogs.com/yelanggu/p/5196156.html // 然后反射实例化,运行它! // https://www.cnblogs.com/yanshanshuo/p/3905621.html void RunIAutoGo(string methodName = "Initialize") { const string iAutoGo = "IAutoGo"; var typeList = new List<RunClass>(); //储存 foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())//当前的应用程序域,也就是acad或者gcad的域 { foreach (Type getTypes in assembly.GetTypes())//获取类型集合 { foreach (Type getInterfaces in getTypes.GetInterfaces())//获取接口集合 { if (getInterfaces != null && !string.IsNullOrEmpty(getInterfaces.Name) && getInterfaces.Name == iAutoGo)//找到接口的函数 { //再找里面的Initialize foreach (MemberInfo member in getTypes.GetMembers())//获得它的成员(函数 方法)的信息集合 { if (member != null && !string.IsNullOrEmpty(member.Name)) { if (member.Name == methodName) { string namePace = Assembly.GetExecutingAssembly().ToString(); //命名空间 string className = member.ReflectedType.FullName; //类名 typeList.Add(new RunClass(namePace, className)); break; } } } } } } } //按照 SequenceId 排序 typeList = typeList.OrderBy(runClass => runClass.SequenceId).ToList(); var sb = new StringBuilder(); int num = 0; foreach (var item in typeList) { try { item.Run(methodName); } catch (System.Exception e) { num++; sb.Append("错误"); sb.Append(num.ToString()); sb.Append("\n\r"); sb.Append("探索接口RunIAutoGo出错,错误NamePace:\n\r"); sb.Append(item.NamePace); sb.Append("\n\r错误ClassName:\n\r"); sb.Append(item.ClassName); sb.Append("\n\r错误信息:\n\r"); sb.Append(e.Message); sb.Append("\n\r\n\r"); } } if (sb.Length > 0) { MessageBox.Show(sb.ToString(), "惊惊连盒"); } } }
封存上面的,之后也不用动了....
任何需要实现启动运行的函数,都去实现 : IAutoGo
注意一下
public class Test : IAutoGo { public Sequence SequenceId() { //最好只使用一次,用于初始化工具集的路径之类的优先项 return Sequence.First; //其余均使用last //return Sequence.Last; } public void Initialize() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;//命令栏交互 ed.WriteMessage("惊惊博客是 https://www.cnblogs.com/JJBox/ "); } public void Terminate() { } }