cad.net IExtensionApplication接口的妙用 分开写"启动运行"函数 20191227更新


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

 

    


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM