C#实现插件式架构

来源:互联网 发布:宇宙有多大 知乎 编辑:程序博客网 时间:2024/06/05 05:03

1.定义插件接口,将其编译为DLL

namespace PluginInterface
{
    public interface IShow
    {
        string show();
    }
}

2 .编写插件,引用上面的DLL,实现上面定义的接口,也编译为DLL

//插件A

namespace PluginInterface
{
    public class PluginA:IShow
    {
        public string show()
        {
            return "插件A";
        }

    }
}

//插件B

namespace PluginB
{
    public class PluginB:IShow
    {

        public string show()
        {
            return "插件B";
        }

    }
}

 

3,在程序中使用插件,需要引用定义插件接口的DLL

namespace testPlugin
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //查找所有的插件的路径
        private List<string> FindPlugin()
        {
            List<string> PluginPaths = new List<string>();
            try
            {
                //获取当前程序的启动路径
                string path = Application.StartupPath;
                //合并路径,指向插件所在的目录
                path = System.IO.Path.Combine(path, "Plugins");
                foreach (string fileName in System.IO.Directory.GetFiles(path, "*.dll"))
                {
                    PluginPaths.Add(fileName);
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }


            return PluginPaths;
        }


        //载入对象
        //是在Assembly asm 中查找类型,原来没有这参数
        private object LoadObject(Assembly asm,string className, string interfaceName, object[] param)
        {
            try
            {
                //取得className的类型
                //Type t = Type.GetType(className); 原来是这么写的,无论如何都是返回的null
                Type t = asm.GetType(className);

                if (t == null
                 || !t.IsClass   //是否是类
                 || !t.IsPublic //是否是公共
                 || t.IsAbstract //是否为抽象类
                 || t.GetInterface(interfaceName) == null) //是否实现了指定的接口
                {
                    return null;
                }

                //创建对象
                object o = Activator.CreateInstance(t, param);
                if (o == null)
                {
                    //创建失败返回null
                    return null;
                }

                return o;
            }
            catch
            {
                //出现异常返回null
                return null;
            }
        }

 


        //移除无效的插件返回正确的插件路径列表 invalid :无效的
        private List<string> DeleteInvalidPlugin(List<string> PluginPaths)
        {
            string interfaceName = typeof(IShow).FullName;
            List<string> RightPluginPaths = new List<string>();
            //遍历所有的插件
            foreach (string fileName in PluginPaths)
            {
                try
                {
                    Assembly asm = Assembly.LoadFile(fileName);
                    // 遍历导出的插件类
                    foreach (Type t in asm.GetExportedTypes())
                    {
                        //查找指定接口
                        IShow plugin = LoadObject(asm
    , t.FullName, interfaceName, null) as IShow;
                        //如果找到,将插件路径添加到RightPluginPaths,并结束循环
                        if (plugin != null)
                        {
                            RightPluginPaths.Add(fileName);
                            break;
                        }
                    }
                }
                catch
                {
                    MessageBox.Show(fileName+"不是有效的插件");
                }
            }


            return RightPluginPaths;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            List<string> PluginPaths = FindPlugin();
            PluginPaths = DeleteInvalidPlugin(PluginPaths);
            foreach (string path in PluginPaths)
            {
                try
                {
                    //获得 文件名称
                    string asmFile = path;
                    string asmName = System.IO.Path.GetFileNameWithoutExtension(asmFile);
                    if (asmFile != string.Empty)
                    {

                        // 利用反射,构造DLL文件的实例
                        System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom(asmFile);

                        //利用反射,从程序集(DLL)中,提取类,并把此类实例化

                        //原来这么写的,无法实例化
                        // PluginInterface.IShow iShow = (PluginInterface.IShow)System.Activator.CreateInstance(asm.GetType(asmName + "Namespace." + asmName + "Class"));
                        Type[] t = asm.GetExportedTypes();
                        foreach (Type type in t)
                        {
                            if (type.GetInterface(typeof(IShow).FullName) != null)
                            {
                                PluginInterface.IShow iShow = (PluginInterface.IShow)System.Activator.CreateInstance(type);
                                // 在主程序中使用这个类的实例
                                label2.Text += iShow.show();
                            }
                        }
                    }
                }

                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }

            }

        }
    }
}