依赖注入的生命周期
生命周期主要有以下三种
-
Transient:每次请求都会创建一个新的实例。这是最常见的生命周期选项。
-
Scoped:在同一次请求中始终返回同一实例。如果在不同的请求中,将会创建一个新的实例。
-
Singleton:每次请求都返回同一个实例,即在首次请求时创建的实例。
安装NuGet包
首先,我们先安装 Microsoft.Extensions.DependencyInjection这是Microsoft提供的依赖注入框架。
生命周期Transient
创建一个类,包含一个属性(Name)和一个方法(SayHi)
public class TestServicesImp
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine("Hello:"+Name);
}
}
👻通过ServiceCollection创建了一个服务容器,然后通过AddTransient方法将TestServicesImp类型注册到这个服务容器中。这里使用的是瞬时生命周期,也就是每次从容器中获取TestServicesImp类型时,都会创建一个新的实例。
public class Program
{
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<TestServicesImp>();
using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
{
var t1 = sp.GetService<TestServicesImp>();
t1.Name = "张三";
t1.SayHi();
var t2 = sp.GetService<TestServicesImp>();
t2.Name = "李四";
t2.SayHi();
var referenceEquals = object.ReferenceEquals(t1, t2);
Console.WriteLine(referenceEquals);
}
}
}
运行结果!因为在瞬时生命周期中,每次获取服务都会创建新的实例。 因此通过object.ReferenceEquals方法比较了t1和t2是否是同一个实例,结果会输出false
生命周期Scoped
我们将上面代码中的服务注册AddTransient方法换成AddScoped,然后t2.SayHi();换成t1.SayHi();,再试一次。
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<TestServicesImp>();
using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
{
var t1 = sp.GetService<TestServicesImp>();
t1.Name = "张三";
t1.SayHi();
var t2 = sp.GetService<TestServicesImp>();
t2.Name = "李四";
t1.SayHi();
var referenceEquals = object.ReferenceEquals(t1, t2);
Console.WriteLine(referenceEquals);
}
}
发现这次的比较结果为true,并且第二次调用SayHi也是使用t1,但依然输出了李四,因此可以得出,两次获取服务得到的是同一个实例。
👻我们对代码再进行改造一下,创建一个新的服务作用域,通过这个作用域的ServiceProvider对象获取了另一个TestServicesImp的实例t2。
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<TestServicesImp>();
using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
{
var t1 = sp.GetService<TestServicesImp>();
t1.Name = "张三";
using (IServiceScope scope = sp.CreateScope())
{
var t2 = scope.ServiceProvider.GetService<TestServicesImp>();
t2.Name = "李四";
t1.SayHi();
t2.SayHi();
var referenceEquals = object.ReferenceEquals(t1, t2);
Console.WriteLine(referenceEquals);
}
}
}
因为它们是在不同的Scope中获取的,所以这次的结果是false
生命周期Singleton
我们将服务注册AddScoped方法,换成AddSingleton,然后再执行一次
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<TestServicesImp>();
using (ServiceProvider sp = serviceCollection.BuildServiceProvider())
{
var t1 = sp.GetService<TestServicesImp>();
t1.Name = "张三";
using (IServiceScope scope = sp.CreateScope())
{
var t2 = scope.ServiceProvider.GetService<TestServicesImp>();
t2.Name = "李四";
t1.SayHi();
t2.SayHi();
var referenceEquals = object.ReferenceEquals(t1, t2);
Console.WriteLine(referenceEquals);
}
}
}
在输出结果中很显然可以看出使用AddSingleton注册服务,每次请求都返回同一个实例
依赖注入的优缺点
-
提高代码的可维护性:依赖注入使代码结构清晰,每个组件的职责单一,易于理解和维护。
提高系统的灵活性和扩展性:由于组件间依赖的是抽象而不是具体实现,更换或升级系统的某个部分变得更加容易,支持系统的快速迭代和扩展。
-
可能导致性能开销:在某些情况下,依赖注入框架在解析依赖时可能会引入额外的性能开销,特别是在启动时间和内存消耗上。
过度依赖容器:过度使用依赖注入有可能导致开发者过度依赖IoC容器来管理对象,从而忽视了对象生命周期和资源管理的重要性。
原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/81483.html