通常,在实例化对象时调用类构造函数,并将对象需要的任何值作为参数传递给构造函数。 这是依赖注入的一个例子,具体称为构造函数注入。 对象需要的依赖项被注入到构造函数中。

通过将依赖项指定为接口类型,依赖注入可以使具体类型与依赖于这些类型的代码进行解耦。 它通常使用一个容器来存储接口和抽象类型之间的注册和映射列表,以及实现或扩展这些类型的具体类型。

还有其他类型的依赖注入,如属性设置器注入和方法调用注入,但它们不太常见。 因此,本章将仅关注使用依赖注入容器执行构造函数注入。

依赖注入简介

依赖注入是反转控制(IoC)模式的专门版本,其中被反转的关注点是获得所需依赖关系的过程。 使用依赖注入,另一个类负责在运行时将依赖关系注入对象。 以下代码示例显示了在使用依赖注入时ProfileViewModel类的结构:

点击(此处)折叠或打开

  1. public class ProfileViewModel : ViewModelBase
  2. {
  3. private IOrderService _orderService;
  4. public ProfileViewModel(IOrderService orderService)
  5. {
  6. _orderService = orderService;
  7. }
  8. ...
  9. }

ProfileViewModel构造函数接收一个IOrderService实例作为参数,由另一个类注入。 ProfileViewModel类中唯一的依赖关系在接口类型上。 因此,ProfileViewModel类对于负责实例化IOrderService对象的类没有任何知识。 负责实例化IOrderService对象并将其插入到ProfileViewModel类中的类称为依赖注入容器。

依赖注入容器通过提供实例化类实例的功能并根据容器的配置来管理其使用寿命来减少对象之间的耦合。 在创建对象期间,容器将注入对象所需的任何依赖项。 如果这些依赖关系尚未创建,容器首先创建并解析它们的依赖关系。

注意:依赖注入也可以使用工厂手动实施。 但是,使用容器可以通过组装扫描提供诸如生命周期管理和注册等附加功能。

使用依赖注入容器有几个优点:

  • 容器不需要一个类定位其依赖关系并管理其生命周期。
  • 容器允许映射实现的依赖关系而不影响类。
  • 通过允许依赖关系被嘲笑,容器便于测试。
  • 通过允许将新类轻松添加到应用程序中,容器增加了可维护性。

在使用MVVM的Xamarin.Forms应用程序的上下文中,依赖注入容器通常用于注册和解析视图模型,以及注册服务并将其注入到视图模型中。

有许多依赖注入容器可用,eShopOnContainers移动应用程序使用Autofac来管理应用程序中的视图模型和服务类的实例化。 Autofac有助于构建松散耦合的应用程序,并提供依赖注入容器中常见的所有功能,包括注册类型映射和对象实例的方法,解析对象,管理对象生命周期,以及将依赖对象注入到其解析的对象的构造器中。 有关Autofac的更多信息,请参阅readthedocs.io上的Autofac

在Autofac中,IContainer接口提供依赖注入容器。 图3-1显示了使用此容器时的依赖关系,它实例化IOrderService对象并将其注入到ProfileViewModel类中。

图3-1:使用依赖注入时的依赖关系

在运行时,容器必须知道它应该实例化的IOrderService接口的哪个实现,然后才能实例化一个ProfileViewModel对象。 这涉及到:

  • 容器决定如何实例化实现IOrderService接口的对象。 这被称为注册。
  • 实例化实现IOrderService接口的对象的容器和ProfileViewModel对象。 这被称为决议。

最终,应用程序将完成使用ProfileViewModel对象,它将可用于垃圾回收。 此时,如果其他类不共享相同的实例,垃圾收集器应该处理IOrderService实例。

???? 提示:写入容器不可知代码。 始终尝试编写与容器无关的代码,以将应用与正在使用的特定依赖关系容器分离。

注册

在将依赖关系注入到对象之前,必须首先向容器注册依赖关系的类型。 注册类型通常涉及将容器传递给实现接口的接口和具体类型。

通过代码在容器中注册类型和对象有两种方法:

  • 使用容器注册类型或映射。 当需要时,容器将构建一个指定类型的实例。
  • 将容器中的现有对象注册为单例。 当需要时,容器将返回对现有对象的引用。

???? 提示:依赖注射容器并不总是适合的。 依赖注入引入了对小应用程序可能不合适或有用的额外的复杂性和要求。 如果类没有任何依赖关系,或者不是其他类型的依赖关系,则将它放在容器中可能是没有意义的。 另外,如果一个类具有一组依赖关系,并且永远不会改变,那么将它放在容器中可能是没有意义的。

需要依赖注入的类型的注册应该通过应用程序中的单一方法执行,并且应该在应用程序的生命周期早期调用此方法,以确保应用程序知道其类之间的依赖关系。 在eShopOnContainers手机应用程序中,这是由ViewModelLocator类执行的,该类构建了IContainer对象,并且是应用程序中唯一持有该对象的引用的类。 以下代码示例显示了eShopOnContainers移动应用程序如何在ViewModelLocator类中声明IContainer对象:

点击(此处)折叠或打开

  1. private static IContainer _container;

类型和实例在ViewModelLocator类中的RegisterDependencies方法中注册。 这是通过首先创建一个ContainerBuilder实例来实现的,该实例在以下代码示例中被演示:

点击(此处)折叠或打开

  1. var builder = new ContainerBuilder();

然后将类型和实例注册到ContainerBuilder对象,并且以下代码示例演示了最常见的类型注册形式:

点击(此处)折叠或打开

  1. var builder = new ContainerBuilder();

此处显示的RegisterType方法将接口类型映射到具体类型。 它通知容器来实例化一个RequestProvider对象,当它实例化一个需要通过构造函数注入IRequestProvider的对象。

也可以直接注册具体类型,而不需要从接口类型映射,如下面的代码示例所示:

点击(此处)折叠或打开

  1. builder.RegisterType();

ProfileViewModel类型解析后,容器将注入其所需的依赖关系。

Autofac还允许实例注册,其中容器负责维护对类型的单例实例的引用。 例如,以下代码示例显示了当ProfileViewModel实例需要IOrderService实例时,eShopOnContainers移动应用程序如何注册具体类型:

点击(此处)折叠或打开

  1. builder.RegisterType().As().SingleInstance();

此处显示的RegisterType方法将接口类型映射到具体类型。 SingleInstance方法配置注册,以便每个从属对象接收相同的共享实例。 因此,只有一个OrderService实例将存在于容器中,该对象由需要通过构造函数注入IOrderService的对象共享。

实例注册也可以使用RegisterInstance方法执行,这在下面的代码示例中被证明:

点击(此处)折叠或打开

  1. builder.RegisterInstance(new OrderMockService()).As();

这里显示的RegisterInstance方法创建一个新的OrderMockService实例并将其注册到容器。 因此,容器中只存在一个OrderMockService实例,该实例由需要通过构造函数注入IOrderService的对象共享。

按照类型和实例注册,必须构建IContainer对象,这在以下代码示例中进行了说明:

点击(此处)折叠或打开

  1. _container = builder.Build();

在ContainerBuilder实例上调用Build方法构建一个新的依赖关系注入容器,其中包含已经创建的注册。

????提示:将IContainer视为不可变的。 虽然Autofac提供了更新方法来更新现有容器中的注册,但应尽可能避免调用此方法。 建造容器后,修改容器是有风险的,特别是在容器已被使用的情况下。有关详细信息,请参阅在readthedocs.io上考虑容器为不变的

解析度

注册一个类型后,可以将其解析或注入为依赖关系。 当一个类型被解析并且容器需要创建一个新的实例时,它会将任何依赖项注入实例。

一般来说,当一个类型被解决时,三件事之一发生:

1. 如果类型尚未注册,容器将引发异常。

2. 如果类型已经注册为单例,容器返回单例实例。 如果这是第一次调用该类型,容器将在需要时创建它,并保留对它的引用。

3. 如果类型未注册为单例,容器返回一个新实例,并且不保留对它的引用。

以下代码示例显示如何解决先前已注册Autofac的RequestProvider类型:

点击(此处)折叠或打开

  1. var requestProvider = _container.Resolve();

在此示例中,要求Autofac解析IRequestProvider类型的具体类型以及任何依赖关系。 通常,当需要特定类型的实例时调用Resolve方法。 有关控制已解析对象的生命周期的信息,请参阅管理已解决对象的生命周期

以下代码示例显示了eShopOnContainers移动应用程序如何实例化查看模型类型及其依赖关系:

点击(此处)折叠或打开

  1. var viewModel = _container.Resolve(viewModelType);

在此示例中,要求Autofac解析所请求视图模型的视图模型类型,容器还将解析任何依赖关系。 解析ProfileViewModel类型时,解析的依赖关系是一个IOrderService对象。 因此,Autofac首先构造一个OrderService对象,然后将其传递给ProfileViewModel类的构造函数。 有关eShopOnContainers移动应用程序如何构建视图模型并将其与视图相关联的更多信息,请参阅使用视图模型定位器自动创建视图模型

注意:使用容器注册和解析类型具有性能成本,因为容器使用反射来创建每种类型,特别是如果为应用程序中的每个页面导航重建依赖关系。 如果有很多或很深的依赖,创造的成本可以显着增加。

管理已解决对象的使用寿命

注册类型后,Autofac的默认行为是在每次解析类型时创建一个新的注册类型实例,或者依赖机制将实例注入其他类时。 在这种情况下,容器不会保留对已解析对象的引用。 但是,注册实例时,Autofac的默认行为是将对象的生命周期作为单例进行管理。 因此,当容器在范围内时,该实例保留在范围内,并且当容器超出范围并被垃圾回收时,或者当代码明确地处置该容器时,该实例将被保留。

Autofac实例范围可用于指定Autofac从注册类型创建的对象的单例行为。 Autofac实例作用域管理由容器实例化的对象生命周期。 RegisterType方法的默认实例范围是InstancePerDependency作用域。 但是,SingleInstance范围可以与RegisterType方法一起使用,以便容器在调用Resolve方法时创建或返回类型的单例实例。 以下代码示例显示了如何指示Autofac创建NavigationService类的单例实例:

点击(此处)折叠或打开

  1. builder.RegisterType().As().SingleInstance();

INavigationService接口第一次解析后,容器将创建一个新的NavigationService对象,并保留对它的引用。 在INavigationService接口的任何后续分辨率上,容器返回对先前创建的NavigationService对象的引用。

注意:当容器被处理时,SingleInstance scope将配置创建的对象。

Autofac包含其他实例范围。 有关更多信息,请参阅readthedocs.io上的实例范围

概要

依赖注入可以使具体类型与依赖于这些类型的代码进行解耦。 它通常使用一个容器来存储接口和抽象类型之间的注册和映射列表,以及实现或扩展这些类型的具体类型。

Autofac有助于构建松散耦合的应用程序,并提供依赖注入容器中常见的所有功能,包括注册类型映射和对象实例的方法,解析对象,管理对象生命周期以及将依赖对象注入到其解析的对象的构造器中。

使用Xamarin.Forms的企业应用程序模式(电子书)--依赖注入相关推荐

  1. 使用Xamarin.Forms的企业应用程序模式(电子书)--访问远程数据

    许多现代的基于Web的解决方案利用由Web服务器托管的Web服务来为远程客户端应用程序提供功能. Web服务公开的操作构成Web API. 客户端应用程序应该能够在不知道API暴露的数据或操作如何实现 ...

  2. dagger2 注入_如何使用Dagger 2在您的应用程序中实现依赖注入

    dagger2 注入 Kriptofolio应用程序系列-第4部分 (Kriptofolio app series - Part 4) Dependency injection will signif ...

  3. 依赖注入(di)模式_Java依赖注入– DI设计模式示例教程

    依赖注入(di)模式 Java Dependency Injection design pattern allows us to remove the hard-coded dependencies ...

  4. 如何在.NET Core控制台程序中使用依赖注入

    背景介绍 依赖注入(Dependency Injection), 是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度.在.NET Core MVC中 我们可以在Startup.cs文件的Co ...

  5. Spring-单例模式和依赖注入

    设计模式 参考:https://www.cnblogs.com/android-blogs/p/5530239.html 1. Spring管理的对象的作用域与生命周期(不常用) 由Spring管理的 ...

  6. 用Xamarin.Forms创建移动应用程序

    --针对iOS,Android和Windows的跨平台C#编程 慢慢的准备翻译这本书.官方发布的第一版.一边翻译一边学习. 第一章:第一部分,http://blog.chinaunix.net/uid ...

  7. C#使用Xamarin开发可移植移动应用(1.入门与Xamarin.Forms页面),附源码

    前言 系列目录 C#使用Xamarin开发可移植移动应用目录 什么是Xamarin? Xamarin始创于2011年,旨在使移动开发变得难以置信地迅捷和简单. Xamarin的产品简化了针对多种平台的 ...

  8. Xamarin.Forms 简介

    An Introduction to Xamarin.Forms 来源:http://developer.xamarin.com/guides/cross-platform/xamarin-forms ...

  9. Xamarin.Forms入门-使用 Xamarin.Forms 来创建跨平台的用户界面

    Xamarin.Forms 是一个跨平台的.基于原生控件的UI工具包,开发人员可以轻松的创建适用于 Android,iOS 以及 Windows Phone的用户界面.Xamarin.Forms 通过 ...

最新文章

  1. 以Java 8 为基准
  2. JSValidation 配置文件
  3. maven整合S2SH
  4. 基于opencv的手写数字字符识别
  5. 《Python面向对象编程指南》——2.7 __del__()方法
  6. 拼多多店铺数据分析有什么作用?哪些数据是有用的?
  7. LaTeX:求和,积分,(上、下)极限,收敛符号,上下确界等
  8. Intel® 2019网络技术研讨会圆满落幕
  9. Oracle 数据统计计算
  10. 行式数据库 VS 列式数据库
  11. SpringCloud微服务项目实战 - 6.延迟任务
  12. [源码和文档分享]基于java的葫芦娃大战妖精
  13. FF直连支付宝问题汇总
  14. Day02 Jinja2模板引擎Bootstrap
  15. 现代金融经济的眼重看历史[程序员学经济二]
  16. 简单双向LSTM模型实战项目
  17. 软件评审一般参加的人员
  18. 乌拉姆数列 Euler167
  19. 手把手教你分析电路之电动车防盗器喇叭驱动
  20. 【中航机考测试感悟】

热门文章

  1. 怎么查MATLAB中的newrbf,已经有了输入输出数据,如何在matlab中建立RBF神经网络
  2. python实现矢量分级渲染_OpenLayer3实现分级渲染(初级版本)
  3. MapReduce执行WordCount操作
  4. MySQL存储引擎InnoDB,MyISAM
  5. luogu P1058 立体图
  6. 值引用和引用问题分析
  7. CC++动态分配内存(手动分配内存)三种方式
  8. Android Chart框架 MPAndroidChart 坐标轴设置
  9. C++中this指针的用法详解
  10. envi插件大津法_IDL打开科学数据集