Unity是微软官方提供的一个Ioc容器,用来实现依赖注入,减少代码之间的耦合程度。使用Unity实现Ioc方式有两种,一种是使用代码方式实现,一种是利用配置文件来实现。
我们先来看一下代码方式是如何实现的。我们先定义 IPay接口,IOrder接口,再定义WeChatPay,AliPay,Order三个类。
/// <summary> /// 支付接口 /// </summary> public interface IPay { string Pay(); } public interface IOrder { string ToPay(); }
/// <summary> /// 微信支付 /// </summary> public class WeChatPay :IPay { public string Pay() { return "微信支付"; } }
/// <summary> /// 支付宝支付 /// </summary> public class AliPay : IPay { public string Pay() { return "支付宝支付"; } }
/// <summary> /// 订单 /// </summary> public class Order : IOrder { /// <summary> /// 订单支付方式 /// </summary> public IPay _iPay; //构造函数注入:可以不写,因为Unity解析时默认会找参数最多的构造函数 [InjectionConstructor] public Order(IPay iPay) { _iPay = iPay; } [Dependency]//属性注入 public IPay _iPayProperty { get; set; } [InjectionMethod]//方法注入 public void PayInit(IPay ipay) { this._iPay = ipay; } public string ToPay() { return this._iPay.Pay(); } }
接着,我们可以使用代码的方式来使用Unity
//创建一个Unity空容器 IUnityContainer container = new UnityContainer(); //向Unity容器注入WeChatPay container.RegisterType<IPay, WeChatPay>(); //向Unity容器注入AliPay,使用命名注册,解析的时候也需要使用命名获取实例 container.RegisterType<IPay, AliPay>("alipay"); var obj = container.Resolve<IPay>(); Console.WriteLine(obj.Pay()); obj = container.Resolve<IPay>("alipay"); Console.WriteLine(obj.Pay()); container.RegisterType<IOrder, Order>(); //Unity解析的时候会按照:构造函数注入 --> 属性注入 --> 方法注入的顺序进行解析 var order = container.Resolve<IOrder>(); Console.WriteLine($"Order.ToPay: {order.ToPay()}");
Console.ReadLine();
运行得到结果
那么,Unity注入类型的生命周期有哪些呢?
//生命周期 IUnityContainer container = new UnityContainer(); //默认瞬时,每一次都是全新生成 container.RegisterType<IOrder, Order>(); container.RegisterType<IOrder, Order>(new TransientLifetimeManager()); //容器单例 container.RegisterType<IOrder, Order>(new ContainerControlledLifetimeManager()); //线程单例 container.RegisterType<IOrder, Order>(new PerThreadLifetimeManager()); var phone1 = container.Resolve<IPhone>(); var phone2 = container.Resolve<IPhone>(); Console.WriteLine(object.ReferenceEquals(phone1, phone2)); //结果为true //分级容器单例 container.RegisterType<IOrder, Order>(new HierarchicalLifetimeManager()); IUnityContainer childContainer = container.CreateChildContainer(); //外部可释放单例 container.RegisterType<IOrder, Order>(new ExternallyControlledLifetimeManager()); //循环引用 不推荐 container.RegisterType<IOrder, Order>(new PerResolveLifetimeManager());
接下来我们再来看下Unity使用配置文件的方式该如何实现依赖注入。我们在项目中新建一个文件夹Config,然后再创建unity.config文件。
<configuration> <configSections> <!--<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>--> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> </configSections> <unity> <!--<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>--> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/> <containers> <container name="IocContainer"> <!-- 格式:类名,程序集名称 --> <register type="IocDemo.IService.IOrder,IocDemo.IService" mapTo="IocDemo.Service.Order, IocDemo.Service"/> <register type="IocDemo.IService.IPay,IocDemo.IService" mapTo="IocDemo.Service.AliPay, IocDemo.Service" name="alipay"/> <register type="IocDemo.IService.IPay, IocDemo.IService" mapTo="IocDemo.Service.WeChatPay, IocDemo.Service"/> </container> </containers> </unity> </configuration>
然后在程序中使用ExeConfigurationFileMap来装载该配置文件
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "Config\unity.config");//找配置文件的路径 Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); IUnityContainer container = new UnityContainer(); section.Configure(container, "IocContainer"); IOrder order = container.Resolve<IOrder>(); Console.WriteLine(order.ToPay()); IPay aliPay = container.Resolve<IPay>("alipay"); Console.WriteLine(aliPay.Pay()); Console.ReadLine();
我们也可以在配置文件中指定生命周期,构造函数初始值
<register type="IocDemo.IService.IOrder,IocDemo.IService" mapTo="IocDemo.Service.Order,IocDemo.Service"> <lifetime type="transient" /> <constructor> <!--<param name="id" type="System.Int32" value="3" />--> <param name="iPay" type="IocDemo.IService.IPay,IocDemo.IService"></param> </constructor> </register>