zoukankan      html  css  js  c++  java
  • 一起谈.NET技术,.NET动态调用DLL的方法 狼人:

      很多软件都是可插拔的,最知名的便是微软的Windows操作系统。你可以在Windows操作系统上安装QQ,也可卸掉QQ,这便是可插拔。这里不谈Windows的实现,因为太过复杂。本文就谈谈管理软件的可插拔的实现。相对Windows操作系统,QQ就是它的一个插件。所以可以简单的将开发可插拔的软件分为两个部分。一个是主应用程序的开发,一个是插件的开发。

      比Windows小的,常见的可插拔的软件是MSN。MSN主应用程序由MS开发,还存在一些MSN插件开发商,国内好像也有不少,这些插件开发商通过在插件中植入广告获取利润。MS不可能提高源代码给这些开发商,那么MSN的主应用程序和MSN的插件是如何衔接起来的呢。我想应该是MS提供了一些接口和方法供开发商使用,估计有个api之类的东西,所以开发可插拔的应用系统分为三个部分。

      1、主应用程序的开发

      2、公用接口的开发

      3、插件的开发

      了解了这些以后,下面通过一个实例来说明。这个实例的原则是可扩展性强,能向下兼用。

      业务需求是:老系统每当逢年过节的时候,会通过邮件给用户发送一些祝福的邮件。现在流行手机和MSN(QQ没有借口)之后,客户希望系统能通过手机短信和MSN的消息给用户送去祝福。现在我们需要开发手机短信和MSN留言两个插件,然后将它们安装到系统中去。

      实现:

      为了简单起见,这里使用控制台应用程序,如果你有兴趣,可以修改成asp.net或者Windows Form的。

      定义两个接口:

    public interface IPluginHost
    {
    void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
    void RegisterComponent<T>(T component) where T : class;
    void MailNotice(string messaage);
    }
    public delegate void MenuItemClickedHandler(string name);

      这个接口是主应用程序继承的,现在只有MailNotice功能, AddMenuItem是供插件调用的方法,创建一个菜单。RegisterComponent是插件向主应用程序提供一些方法。

    public interface IPlugin
    {
    void Initialize(IPluginHost pluginHost);
    void DoSomething();
    }

      上面是插件的接口。

      在主应用程序中有一个加载插件的地方。这里的插件是dll,所以我通过反射去加载这些dll。

    public void LoadPlugin()
    {
    foreach (string fileName in Directory.GetFiles(Directory.GetCurrentDirectory() + "\\" + "Plugins", "*.dll"))
    {
    Assembly assembly = Assembly.LoadFile(fileName);
    foreach (Type pluginType in assembly.GetTypes())
    {
    if (!pluginType.IsPublic || pluginType.IsAbstract || pluginType.IsInterface)
    continue;
    Type concreteType = pluginType.GetInterface(typeof(IPlugin).FullName, true);

    if (concreteType != null)
    {
    IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
    plugin.Initialize(this);
    pluginList.Add(plugin);
    break;
    }
    }
    }
    }

      主应用程序执行的代码如下:

    void Start()
    {
    //邮件发送祝福
    MailNotice("中秋快乐");
    //加载插件
    LoadPlugin();
    //运行插件
    if (pluginList.Count > 0)
    {
    foreach (IPlugin plugin in pluginList)
    {
    plugin.DoSomething();
    }
    }

    Console.ReadLine();
    }

      运行结果如下:

    hhqqqq

      开发两个插件,都继承IPlugin。

      手机短信通知插件:

    public class PluginA : IPlugin
    {

    public void Initialize(IPluginHost pluginHost)
    {
    IPluginHost myApplication = (IPluginHost)pluginHost;
    myApplication.AddMenuItem("Click me", OnClick);

    }
    private void OnClick(string name)
    {
    Console.WriteLine("Omg! You clicked me!");
    }

    public void DoSomething()
    {
    Console.WriteLine("手机短信通知:中秋快乐");
    }

    }

      MSN通知插件:

    public class PluginB : IPlugin
    {

    public void Initialize(IPluginHost pluginHost)
    {
    IPluginHost myApplication = (IPluginHost)pluginHost;
    myApplication.AddMenuItem("Click me", OnClick);

    }
    private void OnClick(string name)
    {
    Console.WriteLine("Omg! You clicked me!");
    }

    public void DoSomething()
    {
    Console.WriteLine("MSN信息通知:中秋快乐");
    }

    }

      插件的目录如下图:

    kkkyyy

      运行效果:

    kkk444

      扩展性和兼容性:

      如果我想在主应用程序中添加一个ShowMessageBox方法。而且这个方法供插件调用。考虑到版本的兼容性,公开的接口是不能修改的。比如:将主应用程序的接口修改成:

    public interface IPluginHost
    {
    void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
    void RegisterComponent<T>(T component) where T : class;
    T GetComponent<T>() where T : class;
    void MailNotice(string messaage);
    void ShowMessageBox(string message);
    }

      那么如何实现呢,很简单,使用依赖注入的方式。添加下面接口:

    public interface IMessageBoxHost
    {
    void ShowMessageBox(string message);
    }

      通过主应用程序的构造函数,将MessageBoxHost对下岗注入到主应用程序,在通过插件的构造函数,将其注入插件之中。

      主应用程序的构造函数:

    public Program(IMessageBoxHost messageBoxHostInstance)
    {
    this.messageBoxHostInstance = messageBoxHostInstance;
    }

      插件构造函数:

    public PluginA(IMessageBoxHost messageBoxHost)
    {
    this.messageBoxHost = messageBoxHost;
    }

      修改实例化插件的代码:

    IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType, new object[] { messageBoxHostInstance });

      这样我们对版本兼容有了保障。

      总结:本文闲谈了可插拔应用程序的开发原理,文章的后面提供了插件和应用程序之间版本兼容的一种方案。有讨论才有进步,欢迎各位留言。

      参考:A Flexible Plugin System    A more extensible way to build plugin system

  • 相关阅读:
    PHP操作redis
    鼠标失去焦点处理办法
    关于HTTP协议,一篇就够了
    什么是 CDN(超形象)
    网站部署之~阿里云系列汇总
    阿里云系列——6.给你的域名使用CDN加速(详细步骤+简单配置)
    mysql备份与还原
    .NET框架之“小马过河”
    .NET使用Bogus生成大量随机数据
    .NET中的值类型与引用类型
  • 原文地址:https://www.cnblogs.com/waw/p/2162701.html
Copyright © 2011-2022 走看看