新文章 网摘 文章 随笔 日记

WinForm插件架构

我一直在开发这种插件体系结构,主要是为了娱乐和教育,它是一个带有一些插件逻辑和两个插件的简单WinForm,我想知道是否有更好的方法。

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Plugin_architecture
{
    public partial class Form1 : Form
    {
    // -----------------------Plugin logic ----------------------------------

    private static IEnumerable<Type> getDerivedTypesFor(Type baseType)
    {
        var assembly = Assembly.GetExecutingAssembly();
        return assembly.GetTypes().Where(baseType.IsAssignableFrom).Where(t => baseType != t);
    }

    public void invokePlugin(object sender, EventArgs e, string pluginIdentifier) {
        Type type = Type.GetType(pluginIdentifier);
        object instance = Activator.CreateInstance(type);
        MethodInfo method = type.GetMethod("start");
        method.Invoke(instance, null);
    }

    public void registerPlugins() {
        // Register plugins at application startup
        IEnumerable<Type> plugins = getDerivedTypesFor(typeof(Plugin));

        foreach(Type plugin in plugins) {

            LinkLabel pluginLabel = new LinkLabel();
            pluginLabel.Text = plugin.ToString();
            pluginLabel.Click += delegate(object sender, EventArgs e) { invokePlugin(sender, e, plugin.ToString()); };
            pluginContainer.Controls.Add(pluginLabel);

        }
    }
    // --------------------------------------------------------------------------

    public Form1()
    {
        InitializeComponent();
        registerPlugins();
        }
    }
}

 

Plugin.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

abstract class Plugin
{
/*
 * Base class for plugins
 * Implement the start method and add any functionality you want. The start method will be
 * called each time the plugin is started. Use the stop method to do any nessesary cleanup.
 */

//public void init() { 
//    // Initialize plugin
//}

//public void register() { 
//    // Register plugin in application
//}

abstract public void start();
abstract public void stop();
}
ServicePlugin.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

class ServicePlugin : Plugin
{
override public void start() { 

    const string message = "Yeahh! Plugins!!";
    const string caption = "Plugins!";
    var result = MessageBox.Show(message, caption,
                                 MessageBoxButtons.OK,
                                 MessageBoxIcon.Information);
}
override public void stop() { 

}
}

 

ClientPlugin.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Plugin_architecture.Plugins.ClientPlugin;

class ClientPlugin : Plugin
{
override public void start() {

    Client frm = new Client();
    frm.Show();
}
override public void stop() { 

    }
}

 

Client.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Plugin_architecture.Plugins.ClientPlugin
{
    public partial class Client : Form
    {
        public Client()
        {
            InitializeComponent();
        }
    }
}

 

该代码可以很好地工作,并且可以毫无问题地进行编译。

3

您应该使用接口而不是抽象类:

public interface IPlugin {
    void Start();
    void Stop();
}

造成这种情况的原因很多,如https://stackoverflow.com/questions/56867/interface-vs-base-class中所述

我还将把插件逻辑从表单中分离出来,并创建一个“ PluginResolver”类来处理这些问题(在这里您可以隐藏不想再碰到的丑陋反射内容)。

就其余代码而言,这是非常基本的,因此添加的内容并不多。

就创建“插件架构”而言,如果不使用依赖注入(或某种依赖解析器),这是一种浪费,因为没有明显的插件相互通信的方式,除非它们耦合在一起(否则会破坏插件体系结构的整体观点),而不是通过具有一组可以注入到特定插件中的根服务,您可以采用一种断开连接的方式,使他们都能使用全部权限来说“主要错误记录器”。

3

看看MEF例如:

// This would preferably be in an assembly outside the main app
[InheritedExport]
public abstract class Plugin
{
    public abstract void Start();
    public abstract void Stop();
}

// This can be in an assembly outside the main app
public class MyPlugin : Plugin
{
    public override void Start()
    {
        // whatever
    }

    public override void Stop()
    {
        // whatever
    }
}

public class CompositionRoot
{
    public CompositionRoot()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new DirectoryCatalog("PluginsPath"));

        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
    }

    [ImportMany(typeof(Plugin))]
    public IEnumerable<Plugin> Plugins { get; set; }

    public void StartPlugins()
    {
        foreach (var plugin in Plugins)
        {
            plugin.Start();
        }
    }

    public void StopPlugins()
    {
        foreach (var plugin in Plugins)
        {
            plugin.Stop();
        }
    }
}
 

https://codereview.stackexchange.com/questions/46790/winform-plugin-architecture

posted @ 2020-04-21 11:32  岭南春  阅读(185)  评论(0)    收藏  举报