利用Unity来实现插件开发
论坛里有许多插件开发的文章,本文就不长篇大论了,说一下我的简单思路:
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 }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace UnityTest { using System.Diagnostics; using System.Windows.Forms; using Microsoft.Practices.Unity.Configuration; using Microsoft.Practices.Unity; using System.Configuration; public interface IMessage { DateTime Time { get ; set ; } string Text { get ; set ; } string ToString( string split); } public class MyMessage:IMessage { public DateTime Time { get ; set ; } public string Text { get ; set ; } public MyMessage( string text,DateTime time) { Text = text; Time = time; } public MyMessage( string text): this (text,DateTime.Now){} public string ToString( string split = " \t " ) { return Time.ToString() + split + Text +split+ GetHashCode(); } } public interface ITrace { IMessage Message { get ; set ; } void Write( string message); } public class ConsoleTrace:ITrace { [Dependency] public IMessage Message { get ; set ; } public void Write( string message) { if (Message != null ) { message = Message.ToString( " \t " ); } Trace.WriteLine(message); } } public class FormTrace:ITrace { public IMessage Message { get ; set ; } public void Write( string message) { if (Message != null ) { message = Message.ToString( " \t " ); } Trace.WriteLine(message); } } public class Class1 { public void test1() { IUnityContainer container = new UnityContainer(); IUnityContainer childContainter = container.CreateChildContainer(); ExeConfigurationFileMap map = new ExeConfigurationFileMap(); map.ExeConfigFilename = " UnityTest.dll.config " ; System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); UnityConfigurationSection section = (UnityConfigurationSection)config.GetSection( " unity " ); var defultContainter = config.AppSettings.Settings[ " DefultContainter " ].Value; section.Configure(container, defultContainter); section.Configure(childContainter, " First " ); // container.LoadConfiguration("Fourth"); // container.RegisterType<ITrace, CosoleTrace>(new ContainerControlledLifetimeManager()); // container.RegisterType<ITrace, FormTrace>(); var message = container.Resolve<IMessage> (); Trace.WriteLine(message.ToString( " \t " )); message.Text = " 1111 " ; var trace = childContainter.Resolve<ITrace> (); trace.Message = message; trace.Write( " fdsfds " ); trace = childContainter.Resolve<ITrace> (); // trace.Message = message; trace.Write( " fdsfds " ); trace = childContainter.Resolve<ITrace> (); trace.Write( " fdsfds " ); // container.LoadConfiguration("Second"); // trace = container.Resolve<ITrace>(); // trace.Write("fdsfds"); } } }
<?xml version= " 1.0 " encoding= " utf-8 " ?> <configuration> <configSections> <section name = " unity " type = " Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration " /> </configSections> <appSettings> <add key = " DefultContainter " value= " ChildContainter " /> </appSettings> <unity xmlns = " http://schemas.microsoft.com/practices/2010/unity " > < namespace name= " UnityTest " /> <assembly name= " UnityTest " /> <container name= " ChildContainter " > <register type= " IMessage " mapTo= " MyMessage " > <constructor> <param name= " text " type= " System.String " value= " abc " /> </constructor> </register> </container> <container name= " First " > <register type= " ITrace " mapTo= " ConsoleTrace " > <lifetime type= " singleton " /> </register> </container> <container name= " Second " > <register type= " ITrace " mapTo= " FormTrace " > <lifetime type= " singleton " /> </register> </container> <container name= " Third " > <register type= " ITrace " mapTo= " ConsoleTrace " > <lifetime type= " perresolve " /> </register> </container> <container name= " Fourth " > <register type= " ITrace " mapTo= " ConsoleTrace " > <lifetime type= " perthread " /> </register> </container> </unity> </configuration>
配置Unity有两种方法:利用配置文件配置;在程序代码中配置。
以 The Unity StopLight QuickStart为例:
在程序中用代码配置,这种方法重新配置需重新编译程序。
IUnityContainer container = new UnityContainer() .AddNewExtension <SimpleEventBrokerExtension> (); .RegisterType <ILogger, TraceLogger> () .RegisterType <IStoplightTimer, RealTimeTimer>();
另一种方式是利用配置文件配置:配置文件配置是应添加
xmlns = " http://schemas.microsoft.com/practices/2010/unity ",这样可以利用xsd架构来智能感知。
<configSections> <section name = " unity " type = " Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration " /> </configSections> <unity xmlns = " http://schemas.microsoft.com/practices/2010/unity " > < namespace name= " StopLight.ServiceInterfaces " /> < namespace name= " StopLight.ServiceImplementations " /> < namespace name= " StopLight.UI " /> < namespace name= " StopLight.Logic " /> <assembly name= " StopLight " /> <container> <register type= " ILogger " mapTo= " TraceLogger " /> <register type= " IStoplightTimer " mapTo= " RealTimeTimer " /> <register type= " Stoplight " > <property name= " Logger " dependencyType= " ILogger " dependencyName= " TraceLogger " /> </register> <register type= " StoplightSchedule " > <property name= " Logger " dependencyType= " ILogger " dependencyName= " TraceLogger " /> </register> <register type= " StoplightPresenter " > <property name= " Stoplight " dependencyType= " Stoplight " dependencyName= " Stoplight " /> <property name= " Schedule " dependencyType= " StoplightSchedule " dependencyName= " StoplightSchedule " /> </register> </container> </unity>
IUnityContainer container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection( " unity " ); section.Configure(container);
分类: .net , C#
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did49084