栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > Unity3D

Prism.Unity 依赖注入(IOC)的使用

Unity3D 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Prism.Unity 依赖注入(IOC)的使用

Prism+Prism.Unity的使用

本文章使用的Prism、Prism.Unity版本:7.2.0.1422

一、使用Prism.Unity构建一个Prism应用

需要说明的是:老版本的Prism,构建WPF应用是新建一个类,继承自UnityBootstrapper。但是新版本的已经不建议这么做了,而是App类直接继承自PrismApplication,具体可以查看新版本中对UnitBootstrapper的注释说明:
源码地址:https://github.com/PrismLibrary/Prism/blob/master/Source/Wpf/Prism.Unity.Wpf/Legacy/UnityBootstrapper.cs

1.新建一个WPF应用

.NET版本选择最高版4.7.2.

2.在Nuget中添加prism.unity


选择Prism.Unity进行安装,安装过程中,会弹出如下界面:

说明Prism.Unity直接或间接依赖了这么多的包,其中:

  • Prism.Core
  • Prism.Wpf
  • Unity.Container

这三个包是必须要了解的

3.在Nuget中添加Unity.Configuration

这个包是当我们需要通过配置文件来实现容器注入时需要用到的

4.修改App.Xaml:

          
    

这里引入了xmlns:prism="http://prismlibrary.com/"的空间,然后使用了PrsimApplication

5.修改App.cs
/// 
/// App.xaml 的交互逻辑
/// 
public partial class App : PrismApplication
{
     protected override Window CreateShell()
     {
         return Container.Resolve();
     }
     protected override void RegisterTypes(IContainerRegistry containerRegistry)
     {

     }
}

这里要引入Prism.Ioc和Prism.Unity两个命名空间

这样我们的第一个Prism引用程序就搭建好了

6.PrsimApplication分析

平时我们启动的App是继承自System.Windows下的Application类

我们将PrismApplication转到定义发现是这样的一种继承关系:

PrismApplicationBase中定义了两个三个抽象方法和若干个虚方法:

/// 
/// Creates the container used by Prism.
/// 
/// The container
protected abstract IContainerExtension CreateContainerExtension();
/// 
/// Used to register types with the container that will be used by your application.
/// 
protected abstract void RegisterTypes(IContainerRegistry containerRegistry);
/// 
/// Creates the shell or main window of the application.
/// 
/// The shell of the application.
protected abstract Window CreateShell();

其中CreateContainerExtension方法被PrismApplication实现了:

protected override IContainerExtension CreateContainerExtension()
{
	return new UnityContainerExtension();
}

所以App继承PrismApplication后,必须实现另外两个抽象方法:RegisterTypes()和CreateShell()

  • RegisterTypes():程序启动时需要注入的类型
  • CreateShell():程序启动时,需要启动的主窗体
二、Prism.Unity的注入

在了解注入之前,我们首先了解一下几个接口及类的关系,他们是:

  • IContainerProvider:抽象第三方IOC框架从容器中拿对象的方法
  • IContainerRegistry:抽象第三方IOC框架注册对象、类型到容器的方法
  • IContainerExtension:将注册对象、取对象统一的接口
  • IContainerExtension< T >:注册对象、取对象的泛型接口
  • UnityContainerExtension:第三方框架Unity整合到Prism的实现方式,运用了适配器模式将Unity整合到Prism中
  • IUnityContainer:Unity中自己容器的接口,Unity有自己去实现

由以上得出的结论是:

  • 取对象用IContainerProvider类型
  • 注册对象用IContainerRegistry类型
  • IContainerExtension类型既可以注册对象,也可以取对象

关系如下图所示:

代码方式的注入,我们只能通过构造函数去注入

1.注入Prism.Wpf已有的类型

上面在分析PrismApplication的时候,PrismApplicationBase类有重写OnStartup方法。查看源码,我们发现OnStartup方法里调用了RegisterRequiredTypes这个方法,这个方法如下:

源码地址:https://github.com/PrismLibrary/Prism/blob/master/Source/Wpf/Prism.Wpf/PrismApplicationBase.cs

/// 
/// Registers all types that are required by Prism to function with the container.
/// 
/// 
protected virtual void RegisterRequiredTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterInstance(_containerExtension);
    containerRegistry.RegisterInstance(_moduleCatalog);
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.RegisterSingleton();
    containerRegistry.Register();
    containerRegistry.Register();
    containerRegistry.Register();
    containerRegistry.Register(); //default dialog host
}

我们关注常用的几个类型:

  • IContainerExtension
  • IMoudleManager
  • IRegionManager
  • IEventAggregator

这样,我们通过Resolve获取到的对象,都可以将以上已经注册在容器里的对象直接通过构造函数注入进去。

例如,App.cs中创建主窗体时:

protected override Window CreateShell()
{
	return Container.Resolve();
}

通过Resolve获取到的对象,我们就可以在MainWindow的构造函数的方法参数中,添加已经注册到容器中的任意个数类型对象,这些类型都将自动注入到MainWindow中

我们可以将IContainerExtension类型的容器继续注入到MainWindow中

public MainWindow(IContainerExtension container)
{
	InitializeComponent();
}

也可以这样注入(注入的参数顺序可以任意):

	public partial class MainWindow : Window
    {
        private IContainerExtension _container;
        private IModuleManager _moudleManager;
        private IRegionManager _regionManager;
        private IEventAggregator _eventAggregator;
        
        public MainWindow(IContainerExtension container, IModuleManager moudleManager,IRegionManager regionManager, IEventAggregator eventAggregator)
        {
            InitializeComponent();
            this._container = container;
            this._moudleManager = moudleManager;
            this._regionManager = regionManager;
            this._eventAggregator = eventAggregator;
        }
    }
2.注入自定义类型

首先我们定义三个类和一个接口

接口:

   	public interface IPerson
    {
        string Sex { get; }
        string Name { get; set; }
    }

两个实现类:

 public class Man : IPerson
 {
 	public string Sex => "男";

	public string Name { get; set; }
}
public class Woman : IPerson
{
    public string Sex => "女";

    public string Name { get; set; }
}

一个动物类,聚合IPerson

 public class Animal
 {
     /// 
     /// 动物的主人
     /// 
     public IPerson BelongPerson;
     public Animal(IPerson owner)
     {
     	this.BelongPerson = owner;
     }
 }
1.通过接口类型来注册:

在App.cs中的RegisterTypes方法中,写入如下代码:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
	containerRegistry.Register();   
}

这样,我们任何时候,通过容器Resolve得到的IPerson类型都是Man类型:

 public MainWindow(IContainerExtension container)
 {
     InitializeComponent();
     this._container = container;

     IPerson person = container.Resolve();//man
}

需要注意的是,Register注册的是非单例的对象,也就是每次Resolve的时候,容器每次帮我们创建了一个新对象。如果需要容器每次给我们的是同一个对象,就需要用RegisterSingleton:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterSingleton();
}

取出单例时:

 public MainWindow(IContainerExtension container)
 {
     InitializeComponent();
     this._container = container;

     IPerson person1 = container.Resolve();//man
     IPerson person2 = container.Resolve();//man
     bool result=person1==person2//person1和person2是同一个对象
}

以上两种类型的注册,均可以按照名称来注册这个类型,比如注册非单例时,可以这样:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
	IPerson p1= containerRegistry.Register("man");  
}

获取这个对象类型时:

public MainWindow(IContainerExtension container)
 {
     InitializeComponent();
     this._container = container;

     IPerson person = container.Resolve("man");//man
}
2.通过实例来注册:

通过实例的方式注册的对象属于单例

通过实例注册,将实例放入容器,可以按照名称来注册这个实例,也可以按照类型来注册这个实例

通过名称来注册实例:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
	IPerson person = new Man();
    containerRegistry.RegisterInstance(person,"man"); 
}

通过类型注册来注册实例:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
	IPerson person = new Man();
    containerRegistry.RegisterInstance(person); 
}
3.自动构造注入:

当我们在RegisterTypes函数中注册了IPerson类型时,我们Resolve其他任意一个具体类时,类的构造函数的参数类型,容器都会尝试自动注入解决,自动注入遵循以下规律:

  • 存在容器中的类型,自动注入到该参数
  • 该参数类型不存在容器中,尝试new一个该类型,也尝试解决该类的构造函数的所有参数类型

例子:

注册IPerson类型:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterInstance(person); 
}

当我们尝试得到一个Animal对象时,由于Animal的构造函数中有IPerson类型,IPerosn类型已经在容器中注册了,所以容器会自动将之前注册的IPerosn类型注入到构造函数中:

public MainWindow(IContainerExtension container)
{
     InitializeComponent();
     this._container = container;

     var animal = container.Resolve();
     string sex=animal.BelongPerson.Sex;//man,IPerson通过Animal的构造函数自动注入进来
}
3.通过配置文件app.config注入类型到容器

通过配置文件注册,需要引用Unity.Configuration

具体通过配置文件注入,请参考Unit.Configuration里的测试用例:

https://github.com/unitycontainer/configuration/tree/master/tests/ConfigFiles

我们在app.config中配置如下:



  
    

在RegisterTypes的代码如下:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
	UnityConfigurationSection section (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
	section.Configure(containerRegistry.GetContainer());
}

取值的时候:

public MainWindow(IContainerExtension container)
{
    InitializeComponent();
    this._container = container;

    IPerson person1 = container.Resolve("A");//man
    IPerson person2 = container.Resolve("B");//woman
    Animal animal = container.Resolve();
    bool result = animal.BelongPerson.Sex == person1.Sex;//true,animal的BelongPerson注入的是A
}
4.通过其他配置文件注入类型到容器

当通过app.config注入类型到容器时,我们通过ConfigurationManager来获取配置文件内容

当是其他配置文件的时候,我们通过如下方式去获取:

假定我们在程序目录下有一个otherConfig.config文件,获取代码如下:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
	string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "otherConfig.config");
	//加载配置文件
    Configuration config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap() { ExeConfigFilename=configPath}, ConfigurationUserLevel.None);
    UnityConfigurationSection section=(UnityConfigurationSection)config.GetSection("unity");
    section.Configure(containerRegistry.GetContainer());
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/900896.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号