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

(完)

原文地址:https://www.cnblogs.com/JJBox/p/10850000.html