被子太轻,压不住想你的心。 --zhu
依赖注入概念
生活中的“控制反转”:
自己发电和用电网的电。
依赖注入(Dependency Injection,DI)是控制反转(Inversion of Control,IOC)思想的实现方式。
依赖注入简化模块的组装过程,降低模块之间的耦合度。
代码控制反转的目的
“怎么创建XX对象”->“我要XX对象”
两种实现方式:
(1)服务定位器(ServiceLocator);
IDbConnection conn=ServiceLocator.GetService<IDbConnection>();
(2)依赖注入(Dependency Injection,DI);
class Demo
{
public IDbConnection Conn{get;set;}
public void InsertDB()
{
IDbConnection cmd=Conn.CreateCommand();
}
}
DI概念
服务(Service):对象;
注册服务;
服务容器:负责管理注册的服务;
查询服务:创建对象及关联对象;
对象生命周期:Transient(瞬态);Scoped(范围);Singleton(单例);
.NET中使用DI
1.Install-Package Microsoft.Extensions.DependencyInjection
2.using Microsoft.Extensions.DependencyInjection
3.ServiceCollection用来构造容器对象IServiceProvider()创建的ServiceProvider,可以用来获取BuildServiceProvider()之前ServiceCollection中的对象。
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddTransient<TestServiceImpl>();
//services.AddSingleton<TestServiceImpl>();
//services.AddScoped<TestServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())//服务定位器 ServiceProvider
{
TestServiceImpl t = sp.GetService<TestServiceImpl>();
t.Name = "Lily";
t.SayHi();
TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
t1.Name = "Tom";
t1.SayHi();
Console.WriteLine(object.ReferenceEquals(t, t1));
t.SayHi();
TestServiceImpl tt1;
using (IServiceScope scope = sp.CreateScope())
{
TestServiceImpl ts= scope.ServiceProvider.GetService<TestServiceImpl>();
t.Name = "Lily";
t.SayHi();
tt1 = ts;
}
using (IServiceScope scope = sp.CreateScope())
{
TestServiceImpl ts = scope.ServiceProvider.GetService<TestServiceImpl>();
t.Name = "Lily";
t.SayHi();
Console.WriteLine(object.ReferenceEquals(tt1, ts));
}
}
Console.Read();
}
}
internal class TestServiceImpl : ITestService
{
public string Name { get ; set; }
public void SayHi()
{
Console.WriteLine($"Hi,I'm {Name}");
}
}
public interface ITestService
{
public string Name { get; set; }
public void SayHi();
}
}
结果:
Hi,I'm Lily
Hi,I'm Tom
False
Hi,I'm Lily
Hi,I'm Lily
Hi,I'm Lily
False
生命周期
1.给类构造函数中打印,看看不同生命周期的对象创建,使用serviceProvider.CreateScope()创建Scope。
2.如果一个类实现了IDisposable接口,则离开作用域之后,容器会自动调用对象的Dispose方法。
3.不要在长生命周期的对象中引用比它短的生命周期的对象。在.NET Core中,会默认抛异常。
4.生命周期的选择:如果类无状态,建议为Singleton;如果类有状态,且有Scpoe控制,建议为Scoped,因为通常这种Scope控制下的代码都是运行在同一个线程中的,没有并发修改的问题;在使用Transient的时候要严谨。
5..NET注册服务的重载方法很多,多看官方文档。
IServiceProvider的服务定位器方法:
1.T GetService
object GetService(Type serviceType)
2.T GetRequireService
object GetRequireService(Type serviceType)
3.IEnumerable
IEnumerable