C# 如何通过单个实例解析通用接口,而不提供单独的具体实现
我有一个类MyBusiness,我在SimpleInjector注册C# 如何通过单个实例解析通用接口,而不提供单独的具体实现,c#,generics,dependency-injection,factory,simple-injector,C#,Generics,Dependency Injection,Factory,Simple Injector,我有一个类MyBusiness,我在SimpleInjector注册 container.RegisterSingleton<MyBusiness>(() => new MyBusiness(Konstants.ConnectionString)); container.RegisterSingleton(()=>newmybusiness(Konstants.ConnectionString)); 现在MyBusiness实现了一个接口IRepositoryProvide
container.RegisterSingleton<MyBusiness>(() => new MyBusiness(Konstants.ConnectionString));
container.RegisterSingleton(()=>newmybusiness(Konstants.ConnectionString));
现在MyBusiness实现了一个接口IRepositoryProvider,如下所示
public interface IRepositoryProvider{
IReader<Entity> Get<Entity>();
IWriter<Entity> Writer<Entity>();
}
公共接口IRepositoryProvider{
IReader Get();
IWriter Writer();
}
IReader和IWriter都继承了IDisposable,实体是某个数据库实体,如果您愿意的话,它是一个POCO类,可能相当多(假设某个工具生成的应用程序中有50多个实体)。MyBusiness为作为通用参数传递的任何实体提供IReader和IWriter的实现,我不为任何IReader,IWriter提供实现
因此,在代码中,它们的用法如下:
var biz = container.GetInstance<MyBusiness>();
using(var users = biz.Get<User>()){
...
}
var biz=container.GetInstance();
使用(var users=biz.Get()){
...
}
由于上述原因,我无法在构造函数注入中使用IReader和IWriter
public class MyUserController:Controller{
public MyUserController(IReader<User> arg){
}
// other functionality
}
公共类MyUserController:Controller{
公共MyUserController(IReader参数){
}
//其他功能
}
上面对IReader IWriter的调用是否可以减少到这个程度
var users = container.GetInstance<IReader<User>>());
var users=container.GetInstance());
这样我就可以轻松地使用IReader和IWriter实现作为依赖注入
IReader和IWriter都实现IDisposable
让我们从这个开始:抽象一般不应该实现IDisposable
。这样做是在通过抽象泄漏实现细节。这意味着您违反了,其中规定:
抽象不应该依赖于细节。细节应该取决于抽象
您正在泄漏实现细节,因为该抽象的所有实现通常不太可能都有需要处置的资源。例如:
- 您可能有不需要处理的模拟或伪实现
- 如果您为这种抽象创建了装饰器或拦截器,那么它们通常没有任何需要处理的资源
IDisposable
。这通常会使应用程序代码更简单,因为客户端代码不再能够调用Dispose
。这意味着要测试的代码更少,出错的事情也更少(因为有人调用了dispose,而他不应该这样做)
然而,这确实意味着,我们应该转移处理该实例的责任,这通常是依赖注入给我们的。它在应用程序(称为)中为我们提供了一个中心位置,它确切地知道何时处理什么
通常,当使用DI容器时,解决方案是将此类类型注册到一个限定范围的生活方式。这意味着实例存在一定的时间。在类的生命周期结束后,DI容器如何代表您控制调用Dispose
对于简单喷油器,通常按如下方式进行:
container.Register(typeof(IReader<>), typeof(ReaderImpl<>), Lifestyle.Scoped);
换句话说,这正是您描述的代码
但是请注意,不要让任何应用程序代码依赖于容器。这是一个众所周知的反模式,叫做。相反,将IRepositoryProvider
实现移动到合成根目录中
IReader和IWriter都实现IDisposable
让我们从这个开始:抽象一般不应该实现IDisposable
。这样做是在通过抽象泄漏实现细节。这意味着您违反了,其中规定:
抽象不应该依赖于细节。细节应该取决于抽象
您正在泄漏实现细节,因为该抽象的所有实现通常不太可能都有需要处置的资源。例如:
- 您可能有不需要处理的模拟或伪实现
- 如果您为这种抽象创建了装饰器或拦截器,那么它们通常没有任何需要处理的资源
IDisposable
。这通常会使应用程序代码更简单,因为客户端代码不再能够调用Dispose
。这意味着要测试的代码更少,出错的事情也更少(因为有人调用了dispose,而他不应该这样做)
然而,这确实意味着,我们应该转移处理该实例的责任,这通常是依赖注入给我们的。它在应用程序(称为)中为我们提供了一个中心位置,它确切地知道何时处理什么
通常,当使用DI容器时,解决方案是将此类类型注册到一个限定范围的生活方式。这意味着
container.GetInstance<IReader<User>>());