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


    原因

    在cad使用netload命令加载dll后,dll自动运行的方法是通过继承IExtensionApplication接口的函数.
    其中构造函数先运行,再运行Initialize方法,cad关闭的时候运行Terminate方法.

    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("
    
    ");
                    sb.Append("探索接口RunIAutoGo出错,错误NamePace:
    
    ");
                    sb.Append(item.NamePace);
                    sb.Append("
    
    错误ClassName:
    
    ");
                    sb.Append(item.ClassName);
                    sb.Append("
    
    错误信息:
    
    ");
                    sb.Append(e.Message);
                    sb.Append("
    
    
    ");
                } 
            }
            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()
        { }
    }
    

    (完)

  • 相关阅读:
    德阳机场大巴
    “以前进行的程序安装创建了挂起的文件操作。运行程序之前,必须重新起动计算机。”的解决办法
    Web程序中网页间数据传递方法小结
    转向姚BLOG
    用ASP.NET在IIS中创建虚拟目录
    TreeView 点击Nodes属性出现“指定的转换无效”错误
    该页正在访问其控制范围之外的数据。这有些危险。是否继续?
    JS的Trim
    JS简明中文教程
    电子数据交换
  • 原文地址:https://www.cnblogs.com/JJBox/p/10850000.html
Copyright © 2020-2023  润新知