論壇里有許多插件開發的文章,本文就不長篇大論了,說一下我的簡單思路:
1、建一個IPlugin接口,每個插件都要繼承這個接口。
2、建一個插件管理類,利用Unity來管理各個插件。
1 using System.Reflection; 2 using Microsoft.Practices.Unity; 3 public interface IPlugin 4 { 5 void LoadPlugin(); 6 string PluginName { get; } 7 } 8 public class PlugInManage 9 { 10 /// <summary> 11 /// 從dll、exe文件中獲取繼承IPluin接口的所有類的類型信息 12 /// </summary> 13 /// <param name="path">文件路徑</param> 14 /// <returns>類型信息(插件名稱,(插件類名稱,插件所在程序集名稱))</returns> 15 public static Dictionary<string, string> Load(string path) 16 { 17 if (!System.IO.Directory.Exists(path)) 18 { 19 throw new System.IO.DirectoryNotFoundException(); 20 } 21 22 Dictionary<string, string> pluins = new Dictionary<string,string>(); 23 var files = System.IO.Directory.GetFiles(path); 24 foreach (var file in files) 25 { 26 if (file.ToLower().EndsWith(".exe") || file.ToLower().EndsWith(".dll")) 27 { 28 var assembly = Assembly.LoadFrom(file); 29 var types = assembly.GetTypes(); 30 foreach (var type in types) 31 { 32 33 if (type.GetInterfaces().Count(c =>c == typeof(IPlugin)) > 0) 34 { 35 36 IPlugin instance = assembly.CreateInstance(type.FullName) as IPlugin; 37 if (instance != null) 38 { 39 _container.RegisterType(typeof(IPlugin), type, type.FullName, new ExternallyControlledLifetimeManager()); 40 41 var name = string.IsNullOrEmpty(instance.PluginName) ? 42 type.FullName : instance.PluginName; 43 name = pluins.ContainsKey(name)?name+"_1":name; 44 pluins.Add(name, type.FullName); 45 } 46 47 } 48 } 49 } 50 } 51 return pluins; 52 } 53 54 static IUnityContainer _container = new UnityContainer(); 55 public static IPlugin Resolve(string name) 56 { 57 GC.Collect(); 58 return _container.Resolve<IPlugin>(name); 59 } 60 61 }
3、注意容器內注冊的類型應為ExternallyControlledLifetimeManager類型的生命周期,外部控制生命周期管理器,這個生命周期管理允許你使用RegisterType和RegisterInstance來注冊對象之間的關系,但是其只會對對象保留一個弱引用,其生命周期交由外部控制,也就是意味着你可以將這個對象緩存或者銷毀而不用在意UnityContainer,而當其他地方沒有強引用這個對象時,其會被GC給銷毀掉。在默認情況下,使用這個生命周期管理器,每次調用Resolve都會返回同一對象(單件實例),如果被GC回收后再次調用Resolve方法將會重新創建新的對象。
測試如下:
using XZL.Plugin; public partial class Form1 : Form { Dictionary<string, string> _plugins; public Form1() { InitializeComponent(); this.Load += new EventHandler(Form1_Load); this.button1.Click += new EventHandler(button1_Click); } void button1_Click(object sender, EventArgs e) { var p = PlugInManage.Resolve(_plugins[listBox1.SelectedItem.ToString()]); p.LoadPlugin(); //GC.Collect(); } void Form1_Load(object sender, EventArgs e) { _plugins = PlugInManage.Load(System.IO.Path.GetDirectoryName(Application.ExecutablePath) + "\\" + "plugins"); foreach (var item in _plugins) { listBox1.Items.Add(item.Key); } } }
1 using XZL.Plugin; 2 public partial class Form1 : Form,IPlugin 3 { 4 public Form1() 5 { 6 InitializeComponent(); 7 } 8 9 public void LoadPlugIn() 10 { 11 this.Show(); 12 } 13 14 15 string IPlugin.PluginName 16 { 17 get { return this.Text; } 18 } 19 }