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
浙公网安备 33010602011771号