什么是控制反转?
控制反转(Inversion of Control,IoC)是面向对象编程中的一种设计原则,主要用于减少代码之间的耦合度。其通过将程序中的对象创建、销毁和对象间的依赖关系的管理权从代码中转移到外部容器或框架,从而实现了控制权的反转。
如何实现控制反转?
控制反转的主要实现方式:依赖注入(需通过服务定位获取依赖注入的根节点)
依赖注入具有传染性:注册完成服务后,通过服务定位器获取服务时,框架会创建服务实例,并一同创建服务在构造函数中赋值的服务(依赖项),称为依赖注入(此时"创建"动作由框架完成,不由调用者完成,所以属于"控制反转",也就是说依赖注入是控制反转的一种实现方式),且该服务所依赖的服务所依赖的服务......均会被创建并注入
换言之,创建创建一个服务时,该服务所依赖的服务(通过构造函数传参)也会被一同创建,称为依赖的传染性
示例
依赖:Microsoft.Extensions.DependencyInjection
服务的生命周期:
Transient 瞬时(获取服务时创建新对象)
Scoped 范围(获取服务时,scope内为同一对象)
Singleton 单例(字面意思)
常用函数:
GetService()返回服务/GetServices()返回所有服务(无则返回null), GetRequiredService()返回服务(无则抛异常)
注:关于GetService()/GetRequiredService(),当存在数个符合条件的服务时, 返回最后注册的服务
补充说明:
以IEnumerable<T>形式依赖注入, 则获取所有符合条件的服务
internal class Program
{
public static void Main(string[] args)
{
// 注册类服务
ServiceCollection serviceCollection = new();
serviceCollection.AddTransient<StartTest_IEnumerable>();
serviceCollection.AddTransient<StartTest>();
// 注册接口服务
serviceCollection.AddTransient<IConfig, ConfigImpl1>();
serviceCollection.AddTransient<IConfig, ConfigImpl2>();
serviceCollection.AddTransient<IConfig, ConfigImpl3>();
serviceCollection.AddTransient<IGetData, GetDataImpl>();
serviceCollection.AddTransient<ITest, TestImpl>();
using (var serverProvider = serviceCollection.BuildServiceProvider())
{
// GetService()返回服务/GetServices()返回所有服务(无则返回null), GetRequiredService()返回服务(无则抛异常)
// GetService()/GetRequiredService(): 当存在数个符合条件的服务时, 返回最后注册的服务
// 以IEnumerable<T>形式依赖注入, 则获取所有符合条件的服务
var startTest_IEnumerable = serverProvider.GetRequiredService<StartTest_IEnumerable>();
startTest_IEnumerable.Start();
//var startTest = serverProvider.GetRequiredService<StartTest>();
//startTest.Start();
//IEnumerable<IConfig> configs = serverProvider.GetServices<IConfig>();
//foreach (var item in configs)
//{
// item.Config();
//}
}
}
class StartTest_IEnumerable
{
private IEnumerable<IConfig> config;
private IGetData getData;
private ITest test;
public StartTest_IEnumerable(IEnumerable<IConfig> config, IGetData getData, ITest test) // 所注册服务为接口, 故参数类型也为接口
{
this.config = config;
this.getData = getData;
this.test = test;
}
public void Start()
{
foreach (var item in config)
{
item.Config();
}
getData.GetData();
test.Test();
}
}
class StartTest
{
private IConfig config;
private IGetData getData;
private ITest test;
public StartTest(IConfig config, IGetData getData, ITest test) // 所注册服务为接口, 故参数类型也为接口
{
this.config = config;
this.getData = getData;
this.test = test;
}
public void Start()
{
config.Config();
getData.GetData();
test.Test();
}
}
interface IConfig
{
public void Config();
}
class ConfigImpl1 : IConfig
{
public void Config()
{
Console.WriteLine("Config1...");
}
}
class ConfigImpl2 : IConfig
{
public void Config()
{
Console.WriteLine("Config2...");
}
}
class ConfigImpl3 : IConfig
{
public void Config()
{
Console.WriteLine("Config3...");
}
}
interface IGetData
{
public void GetData();
}
class GetDataImpl : IGetData
{
public void GetData()
{
Console.WriteLine("GetData...");
}
}
interface ITest
{
public void Test();
}
class TestImpl : ITest
{
public void Test()
{
Console.WriteLine("Test...");
}
}
}