參考 Windows/MSN 架構,可插拔系統包含:
IPluginHost、IPlugin)。IPlugin,由主程式動態載入(DLL)。// 主機介面:插件可呼叫 AddMenuItem、RegisterComponent
public interface IPluginHost
{
void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
void RegisterComponent<T>(T component) where T : class;
void MailNotice(string message);
}
public delegate void MenuItemClickedHandler(string name);
// 插件介面:主程式呼叫 Initialize、DoSomething
public interface IPlugin
{
void Initialize(IPluginHost pluginHost);
void DoSomething();
}
private List<IPlugin> pluginList = new List<IPlugin>();
public void LoadPlugin()
{
string pluginDir = Path.Combine(Directory.GetCurrentDirectory(), "Plugins");
foreach (string fileName in Directory.GetFiles(pluginDir, "*.dll"))
{
Assembly asm = Assembly.LoadFile(fileName);
foreach (Type t in asm.GetTypes())
{
if (!t.IsPublic || t.IsAbstract || t.IsInterface) continue;
Type pluginInterface = t.GetInterface(typeof(IPlugin).FullName);
if (pluginInterface != null)
{
IPlugin plugin = (IPlugin)Activator.CreateInstance(t);
plugin.Initialize(this); // 傳入主機介面
pluginList.Add(plugin);
break; // 假設每個 DLL 只有一個插件
}
}
}
}
void Start()
{
MailNotice("中秋快樂"); // 核心功能
LoadPlugin(); // 載入擴充功能
if (pluginList.Count > 0)
{
foreach (var p in pluginList) p.DoSomething();
}
Console.ReadLine();
}
public class PluginA : IPlugin
{
public void Initialize(IPluginHost host)
{
host.AddMenuItem("Click me", OnClick);
}
private void OnClick(string name) => Console.WriteLine("Omg! You clicked me!");
public void DoSomething() => Console.WriteLine("手機簡訊通知:中秋快樂");
}
public class PluginB : IPlugin
{
public void Initialize(IPluginHost host)
{
host.AddMenuItem("Click me", OnClick);
}
private void OnClick(string name) => Console.WriteLine("Omg! You clicked me!");
public void DoSomething() => Console.WriteLine("MSN 訊息通知:中秋快樂");
}
需求:主程式新增 ShowMessageBox 供插件呼叫,但 不可修改已發布的 IPluginHost。
IMessageBoxHost。IMessageBoxHost 實作。Activator.CreateInstance(type, new object[] { msgBoxHost }) 傳遞。public interface IMessageBoxHost { void ShowMessageBox(string message); }
// 主程式
public Program(IMessageBoxHost mbh) { this.messageBoxHostInstance = mbh; }
// 插件
public PluginA(IMessageBoxHost mbh) { this.messageBoxHost = mbh; }
// 載入時
IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType, new object[] { messageBoxHostInstance });

本文示範從零建立可插拔架構:介面契約、反射載入、主機服務暴露、插件生命週期,並以依賴注入解決介面演進的版本相容難題。完整代碼可參考:Plugin.rar。