切换导航
简历
工具
演示
查询
导航菜单
服务端
30
前端
114
数据库
82
进阶开发
8
桌面程序
2
QA
15
软件使用
36
规范协议
5
操作系统
11
AI
0
复用资源
6
硬件
0
标签
设计模式
框架
大数据
物联网
实现方案
算法
分布式
第三方应用
消息中间件
外部链接
.NET Core SDK和运行时安装包
淘宝 NPM 镜像
查询网
Tables Generator线上表格转换工具
引用cdn在线脚本和样式
首页
进阶开发
控制反转IOC与依赖注入理解
[TOC] ## 1. 依赖注入 **定义:**依赖注入(Dependency Injection)是一种设计模式,它的主要目的是实现松耦合和可测试性。通过将外部依赖的对象通过构造函数参数的方式传入当前对象,可以将对象的依赖关系外部化,使得对象之间的耦合度降低,便于代码的测试和维护。 **依赖注入是通过以下三个部分来实现的:** + 依赖项(Dependency):需要被注入的外部对象或服务。 + 注入器(Injector):负责将依赖项注入到目标对象中,注入器是一种抽象的概念,是指负责将依赖项注入到目标对象的机制或工具(IOC)。 + 目标对象(Target):需要依赖项的目标对象。 通过构造函数参数的方式,目标对象可以获得所需的依赖项,而不需要直接创建或访问该依赖项。这样,依赖项的提供者(通常是IoC容器)可以控制和管理依赖项的生命周期和依赖关系,使得应用程序更加灵活、可维护和可测试 **依赖注入的原理和流程如下:** + 定义依赖项(Dependency):需要被注入的外部对象或服务。通常是一些接口或抽象类。 + 实现依赖项:为依赖项提供具体的实现。这可以是具体的类、工厂或其他实现方式。 + 定义目标对象(Target):需要依赖项的目标对象。这通常是一个具体的类,包含了对依赖项的使用逻辑。 + 注入依赖项:通过构造函数参数的方式,将依赖项注入到目标对象中。注入的方式可以是手动或自动的。 **<span id="dependecy-structure">以下是依赖注入的简单示例代码:</span>** ```csharp // 定义依赖项 public interface IDependency { void PerformAction(); } // 实现依赖项 public class DependencyImplementation : IDependency { public void PerformAction() { // 具体实现逻辑 } } // 定义目标对象 public class Target { private IDependency _dependency; public Target(IDependency dependency) { _dependency = dependency; } public void PerformAction() { _dependency.PerformAction(); } } // 注入依赖项 public static void Main() { var dependency = new DependencyImplementation(); // 创建依赖项实例 var target = new Target(dependency); // 将依赖项注入到目标对象中 target.PerformAction(); // 执行操作 } ``` 在上述示例中,`IDependency` 是依赖项的接口,`DependencyImplementation` 是该接口的具体实现。`Target` 是需要使用依赖项的目标对象,通过构造函数注入 `IDependency` 类型的参数,使得 `Target` 对象可以使用依赖项。在 `Main` 方法中,我们手动创建了依赖项的实例,并通过构造函数将该实例注入到 `Target` 对象中。这样,`Target` 对象就可以使用依赖项执行相应的操作。 通过这种方式,依赖注入将对象的依赖关系外部化,使得对象之间的耦合度降低。同时,由于依赖项的提供者可以控制和管理依赖项的生命周期和依赖关系,使得应用程序更加灵活、可维护和可测试。 >**Tips** > 在依赖注入中,依赖项的提供者通常是一个IoC(控制反转)容器。IoC容器负责管理依赖项的生命周期和依赖关系,并根据需要将依赖项注入到目标对象中。 > **具体来说,IoC容器可以控制和管理以下方面:** + 生命周期管理:IoC容器负责创建和销毁依赖项。当需要使用依赖项时,目标对象通过注入器从容器中获取依赖项的实例,当使用完毕后,容器负责将实例销毁,以释放资源。 + 依赖关系管理:IoC容器负责维护依赖项之间的依赖关系。当某个依赖项需要被注入到目标对象中时,容器负责找到该依赖项并传递给目标对象。 + 配置管理:IoC容器负责管理依赖项的配置信息。这包括识别依赖项的映射关系、依赖项的版本信息等。 ### 1.1. 依赖注入的三种方式 #### 1.1.1. 构造函数注入 上面的示例就是使用的构造函数注入的,详细示例代码[🔍️](#dependecy-structure) #### 1.1.2. 属性注入 **<span id="dependecy-attr">下面是使用属性注入的方式将依赖注入的简单示例代码:</span>** ```csharp // 定义依赖项 public interface IDependency { void PerformAction(); } // 实现依赖项 public class DependencyImplementation : IDependency { public void PerformAction() { // 具体实现逻辑 } } // 定义目标对象 public class Target { public IDependency _dependency { get; set; } public void PerformAction() { _dependency.PerformAction(); } } // 注入依赖项 public static void Main() { var dependency = new DependencyImplementation(); // 创建依赖项实例 var target = new Target(); target._dependency = dependency; // 将依赖项注入到目标对象中 target.PerformAction(); // 执行操作 } ``` #### 1.1.3. 方法注入 **<span id="dependecy-attr">下面是使用函数注入的方式将依赖注入的简单示例代码:</span>** ```csharp // 定义依赖项 public interface IDependency { void PerformAction(); } // 实现依赖项 public class DependencyImplementation : IDependency { public void PerformAction() { // 具体实现逻辑 } } // 定义目标对象 public class Target { private IDependency _dependency; public void SetDependency(IDependency dependency) { _dependency = dependency; } public void PerformAction() { _dependency.PerformAction(); } } // 注入依赖项 public static void Main() { var dependency = new DependencyImplementation(); // 创建依赖项实例 var target = new Target(); target.SetDependency(dependency); // 将依赖项注入到目标对象中 target.PerformAction(); // 执行操作 } ``` *** > **Tips** > 需要注意的是,依赖注入的方式应该根据具体情况进行选择。构造函数注入是最常用的方式,因为它可以在对象创建时就确定所有的依赖关系,并且可以方便地提供默认的依赖对象。属性注入和方法注入通常被认为是不够安全的方式,因为它们可能导致依赖关系在运行时才动态地注入,不利于依赖关系的控制和管理 ## 2. 控制反转 **定义:**控制反转(Inversion of Control,IoC)是一种编程思想,用于将对象的创建和依赖关系的处理交给外部容器来控制。这种思想可以降低代码的耦合度,提高灵活性和可维护性。在编程中,IoC容器常被用于实现依赖注入,即把对象的依赖关系通过外部容器来控制,使得应用程序可以更方便地实现模块化、可插拔和易于测试的特性。 **控制反转解释:**控制反转它是一种将控制权从代码中转移出去,交由外部控制器来负责控制的方式。在IoC中,对象之间的依赖关系由外部容器来负责管理,而不是由代码本身来直接控制。 "反转"这个概念指的是控制权的转移。在传统的编程中,通常会手动创建和管理对象之间的依赖关系,代码会持有对其他对象的直接控制。而在IoC中,外部容器负责创建、管理、注入依赖关系,代码将依赖关系的控制权交给了外部容器。 **下面是一个简单的IOC示例:** + 编写一个依赖服务,到时需要将这个依赖注入到目标对象中,代码如下: ```csharp public interface IService1 { string PerformAction1(); } public interface IService2 { string PerformAction2(); } public class Service1 : IService1 { public string PerformAction1() { return "Service1: Action1 performed."; } } public class Service2 : IService2 { public string PerformAction2() { return "Service2: Action2 performed."; } } ``` + 编写目标对象,需要使用依赖服务的业务类,这里使用构造函数的方式进行依赖的注入 ```csharp public class DependentClass { private IService1 _service1; private IService2 _service2; public DependentClass(IService1 service1, IService2 service2) { _service1 = service1; _service2 = service2; } public void PerformAction() { Console.WriteLine(_service1.PerformAction1()); Console.WriteLine(_service2.PerformAction2()); } } ``` + 利用反射编写一个简单的IOC容器 ```csharp public class Container1 { private Dictionary<Type, object> registeredServices = new Dictionary<Type, object>(); public void Register<TService, TImplementation>() where TService : class where TImplementation : class, TService { registeredServices[typeof(TService)] = Activator.CreateInstance<TImplementation>(); } public void Register<TImplementation>() where TImplementation : class { Type type = typeof(TImplementation); ConstructorInfo[] constructors = type.GetConstructors(); foreach (ConstructorInfo constructor in constructors) { ParameterInfo[] parameters = constructor.GetParameters(); object[] obj = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type a = parameters[i].ParameterType; obj[i] = registeredServices[a]; } if (obj == null || obj.Length == 0) { registeredServices[typeof(TImplementation)] = Activator.CreateInstance<TImplementation>(); } else { registeredServices[typeof(TImplementation)] = Activator.CreateInstance(type, obj); } } } public T GetInstance<T>() where T : class { object serviceInstance; if (registeredServices.TryGetValue(typeof(T), out serviceInstance)) { return (T)serviceInstance; } else { // 如果未找到注册的实例,可以通过反射创建新实例 serviceInstance = Activator.CreateInstance<T>(); registeredServices[typeof(T)] = serviceInstance; return (T)serviceInstance; } } } ``` + 使用这个IOC容器来管理这些依赖 ```csharp public static void Test() { // 创建容器实例 var container = new Container(); // 注册服务实现和接口的映射关系 container.Register<IService1, Service1>(); container.Register<IService2, Service2>(); container.Register<DependentClass>(); // 获取依赖注入的实例 var dependentClass = container.GetInstance<DependentClass>(); // 调用依赖注入的方法 dependentClass.PerformAction(); } ``` 在上述代码中,`Container` 类使用了一个 `Dictionary` 来存储注册的依赖关系。`Register` 方法接受两个类型参数 `TService` 和 `TImplementation`,其中 `TService` 是要注册的接口类型,而 `TImplementation` 是实现了该接口的具体类。在方法内部,通过 `Activator.CreateInstance` 创建了具体类的实例,并将其存储在 `registeredServices` 中。 `GetInstance` 方法用于从容器中获取实例。它首先尝试从 `registeredServices` 中获取对应的实例,如果找到了则直接返回。如果未找到,则通过反射创建新实例,并将其存储在 `registeredServices` 中,然后返回。 这样,通过调用 `container.Register<IService, Service1>();` 、`container.Register<IService, Service2>();` 和 ` container.Register<DependentClass>();`,可以将具体的实现类注册到容器中,并在需要使用时通过 `container.GetInstance<DependentClass>();` 获取到对应的实例。 ### 2.1. C# 常用的IOC **在C#中,常见的IOC容器有以下几种:** + Autofac:是一个轻量级的、可扩展的依赖注入框架,支持多种服务注册方式和多个生命周期管理。 + Ninject:是一个开源的、灵活的依赖注入框架,支持传统的依赖注入和基于接口的依赖注入。 + Castle Windsor:是一个功能齐全、性能高效的依赖注入框架,支持多种服务注册方式和多个生命周期管理。 + Unity:是一个由Microsoft开发的轻量级依赖注入框架,被广泛用于ASP.NET Core应用程序中。 + Simple Injector:是一个轻量级的、高性能的依赖注入框架,专注于提供简单的API和强大的扩展性。 这些IOC容器都提供了相似的功能,可以根据项目的具体需求选择适合的IOC容器 **Simple Injector这个IOC容器的示例:** + 首先需要安装`Simple Injector`这个包,在VS的工具NuGet包管理器中进行查找安装 + 安装完成后编写一个依赖服务,到时需要将这个依赖注入到目标对象中,代码如下: ```csharp public interface IService1 { string PerformAction1(); } public interface IService2 { string PerformAction2(); } public class Service1 : IService1 { public string PerformAction1() { return "Service1: Action1 performed."; } } public class Service2 : IService2 { public string PerformAction2() { return "Service2: Action2 performed."; } } ``` + 编写目标对象,需要使用依赖服务的业务类,这里使用构造函数的方式进行依赖的注入 ```csharp public class DependentClass { private IService1 _service1; private IService2 _service2; public DependentClass(IService1 service1, IService2 service2) { _service1 = service1; _service2 = service2; } public void PerformAction() { Console.WriteLine(_service1.PerformAction1()); Console.WriteLine(_service2.PerformAction2()); } } ``` + 使用Simple Injector这个IOC容器来管理这些依赖 ```csharp public static void Test() { // 创建容器实例 var container = new Container(); // 注册服务实现和接口的映射关系 container.Register<IService1, Service1>(); container.Register<IService2, Service2>(); // 注意这里使用ioc来注册依赖并实例对象,因此这里也需要对DependentClass进行注册,否则Simple Injector会报错,提示DependentClass未被注册 container.Register<DependentClass>(); // 获取依赖注入的实例 var dependentClass = container.GetInstance<DependentClass>(); // 调用依赖注入的方法 dependentClass.PerformAction(); } ``` 在这个示例中,使用Simple Injector IoC容器来管理依赖关系。通过Register方法将服务实现与接口的映射关系注册到容器中,然后使用GetInstance方法获取依赖注入的实例。在获取DependentClass的实例时,容器会自动创建并注入所需的IService1和IService2的实现。这样,就可以通过依赖注入的方式将依赖关系交给外部容器来管理 ### 2.2. IOC与依赖注入的关系 IoC容器负责管理依赖项的生命周期和依赖关系,并根据需要将依赖项注入到目标对象中。 **IoC容器可以控制和管理以下方面:** + 生命周期管理:IoC容器负责创建和销毁依赖项。当需要使用依赖项时,目标对象通过注入器从容器中获取依赖项的实例,当使用完毕后,容器负责将实例销毁,以释放资源。 + 依赖关系管理:IoC容器负责维护依赖项之间的依赖关系。当某个依赖项需要被注入到目标对象中时,容器负责找到该依赖项并传递给目标对象。 + 配置管理:IoC容器负责管理依赖项的配置信息。这包括识别依赖项的映射关系、依赖项的版本信息等。 > 通过以上控制和管理方式,IoC容器可以有效地控制和管理依赖项的生命周期和依赖关系,使得应用程序更加灵活、可维护和可测试。
扫一扫手机看
点击排行
windows 文件资源管理器使用
Layui 弹窗open使用说明
SQL Server 中字符串函数使用
C# 使用QQ邮箱代理做邮件接收功能
SQL Server关于apply的两种形式cross apply 和 outer apply
ASP.NET MVC 模型的自定义验证
nvm安装及常用命令
SQL Server 中数据类型转换
SQL Server 中WITH AS短语的使用
IE浏览器下AJAX缓存问题导致数据不更新的解决办法
订阅号