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() { } }