Microsoft Unity使用-实例注入
Unity是一个轻量级AOP框架,提供构造注入、拦截注入、属性注入、方法注入,使用起来很方便
一、简单实例注入
先看一个应用场景。一个应用程序中我想定义一个窗口,做为用户UI,窗口有高度和宽度两种属性
namespace ConsoleUnityDemo
{
public class MyWindow
{
public int Height { get; set; }
public int Width { get; set; }
}
class Program
{
static void Main(string[] args)
{
MyWindow myWindow = new MyWindow();
myWindow.Height = 80;
myWindow.Width = 100;
Console.WriteLine(string.Format("Width:{0} Height:{1}", myWindow.Width, myWindow.Height));
}
}
}
窗口的高属性会经常改变,所以要将myWindow实例的属性移到配置中,通常会在<appsetting/>中通过<add key />来添加配置,这样的话需要加两个配置,如
<appSettings> <add key="Height" value="200"/> <add key="Width" value="300"/> </appSettings>
但是如果应用程序中有两个MyWindow实例呢?再加上<add key=”Heithgt2”/><add key=”Width2”/>吗?那再多呢?
Unity提供了轻松实例注入的功能,将对象的实例化移到了应用程序的外部。使用Unity要先引用以下类库,Unit下载:http://http://unity.codeplex.com/
Microsoft.Practices.Unity.dll Microsoft.Practices.Unity.Configuration.dll
修改为以下代码
namespace ConsoleUnityDemo { public class MyWindow { public int Height { get; set; } public int Width { get; set; } } class Program { static void Main(string[] args) { UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); UnityContainer unityContainer = new UnityContainer(); unitySection.Configure(unityContainer); //获取容器 MyWindow myWindow = unityContainer.Resolve<MyWindow>("FirstMyWindow"); //取实例 Console.WriteLine(string.Format("Width:{0} Height:{1}", myWindow.Width, myWindow.Height)); } } }
App.config配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="MyWindow" type="ConsoleUnityDemo.MyWindow, ConsoleUnityDemo" /> <container> <register type="MyWindow" name="FirstMyWindow" mapTo ="MyWindow"> <property name="Height" value="80" type="int" /> <property name="Width" value="100" type="int" /> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> </appSettings> </configuration>
configSections中section添加了一个名为Unity容器,<unity/>节点的注册了MyWindow类,别名为MyWindow,type中填写类型的完整名称和类型的命名空间,<container/>节点下<register/>注册一个新实例,这样一来MyWindow实例属性就被移除到程序外部了。实际应用中,通常有多种类型的MyWindow,应该将MyWindow象为接口。
配置文件做如下修改
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="MyWindow" type="ConsoleUnityDemo.MyWindow, ConsoleUnityDemo" /> <alias alias="IWindow" type="ConsoleUnityDemo.IWindow, ConsoleUnityDemo" /> <container> <register type="IWindow" name="FirstMyWindow" mapTo ="MyWindow"> <property name="Height" value="80" type="int" /> <property name="Width" value="100" type="int" /> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> </appSettings> </configuration>
添加alias别名为IWindow的IWindow类型。register注册为IWindow, mapTo为实际要创建的类,这就如同
IWindow MyFirstWindow = new MyWindow
再看看工场模式,创建window改用模块方法:
工场模式中需要IWindow泛化,还需要一个在场类,这样才能和Window解偶,并且需要修改Factory方法才可以创建新的Window。使用Unit容器中<register/>的mapTo属性就可以轻松实现工场模式了,Unity替代了Factory的工作。再看下抽象工场:
现在需要在一种window中创建一个配套的menu,所以使用了抽象工场,在Client中获取实现IAbstracgtFactory的工场就可以创建一套window. 抽象工场中会定义多个,如MyWindowFactory,OtherWindowFactory。在Unity中通过修改Cantoner name属性就可轻松搞写
namespace ConsoleUnityDemo { public interface IWindow { int Height { get; set; } int Width { get; set; } void Show(); } public interface IMenu { string MenuText { get; set; } string MenuColor { get; set; } } public class MyWindow : IWindow { public int Height { get; set; } public int Width { get; set; } public void Show() { Console.WriteLine("Show MyWindow"); } } public class MyMenu : IMenu { public string MenuText { get; set; } public string MenuColor { get; set; } } class Program { static void Main(string[] args) { UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); UnityContainer unityContainer = new UnityContainer(); unitySection.Configure(unityContainer, "AbstractFactory"); //获取容器 IWindow myWindow = unityContainer.Resolve<IWindow>("FirstMyWindow"); //取实例 IMenu myMenu = unityContainer.Resolve<IMenu>("FirstMyMenu"); Console.WriteLine(string.Format("Width:{0} Height:{1}", myWindow.Width, myWindow.Height)); } } }
配置文件如下,将container name属性设置为AbstractFacotry,代码中用unitySection.Configure(unityContainer, "AbstractFactory"); 获取工场。如果增加一个工场,则添加一个Container
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="MyWindow" type="ConsoleUnityDemo.MyWindow, ConsoleUnityDemo" /> <alias alias="IWindow" type="ConsoleUnityDemo.IWindow, ConsoleUnityDemo" /> <alias alias="IMenu" type="ConsoleUnityDemo.IMenu, ConsoleUnityDemo" /> <alias alias="MyMenu" type="ConsoleUnityDemo.MyMenu, ConsoleUnityDemo" /> <container name="AbstractFactory"> <register type="IWindow" name="FirstMyWindow" mapTo ="MyWindow"> <property name="Height" value="80" type="int" /> <property name="Width" value="100" type="int" /> </register> <register type="IMenu" name="FirstMyMenu" mapTo ="MyMenu"> <property name="MenuText" value="testValue" /> <property name="MenuColor" value="ColorValue" /> </register> </container> </unity>
曾经年少多少事 而今皆付谈笑中!