nes*_*h_s 1 c# generics dependency-injection repository-pattern
我有一个基本存储库合同,其他合同扩展,如下所示
public interface IBaseRepository<T> where T : class
{
IList<T> GetContents();
}
Run Code Online (Sandbox Code Playgroud)
然后还有其他合同,如下所示扩展它
public interface IRepository1 : IBaseRepository<MyClass1>
{
}
public interface IRepository2 : IBaseRepository<MyClass2>
{
}
Run Code Online (Sandbox Code Playgroud)
我按如下方式实现IRepository1
public class Repository1 : IRepository1
{
public IList<MyClass1> GetContents()
{
//some code goes here
}
}
Run Code Online (Sandbox Code Playgroud)
同样适用于IRepository2
public class Repository2 : IRepository2
{
public IList<MyClass2> GetContents()
{
//some code goes here
}
}
Run Code Online (Sandbox Code Playgroud)
现在我有一个服务Service1,其中包括如下的IService
public class Service1 : IService
{
}
Run Code Online (Sandbox Code Playgroud)
我想在我的服务构造函数中使用我的基本存储库(IBaseRepository),获取此基本存储库的实例并像这样使用它
public class Service1 : IService
{
private IBaseRepository<T> _baseRepository;
public Service1(IBaseRepository<T> baseRepository)
{
_baseRepository = baseRepository;
}
public MyMethod1()
{
var contentsOfType1 = _baseRepository<MyClass1>.GetContents();
}
public MyMethod1()
{
var contentsOfType2 = _baseRepository<MyClass2>.GetContents();
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我无法做到的.
所以我有一个类型为T的通用基础知识库合同,并有其他合同(接口)扩展基本合同,并指定T将是什么类型.
所有这些合同(扩展通用基础合同)都有各自的实现.
我想要做的是在我的服务类中,实例化这个通用基本契约,并使用它来推断扩展类型(以及实现)并使用基本库中的方法.
所以,如果基本合同是
IBaseRepository<T>
并延长合同
IRepository1 : IBaseRepository<MyClass1>
由...实施
Repository1 : IRepository1
我想在我的服务类中使用它
public class service()
{
*private IBaseRepository<T> _repo;
public service(IBaseRepository<T> repo)
{
*_repo = repo;
}
public void MyMethod()
{
*var x = _repo<MyClass1>.MethodFromIBaseRepository()
}
}
Run Code Online (Sandbox Code Playgroud)
所以它是我想要实现的*标记线,我无法做到.
我正在使用城堡windsor作为DI.
谢谢你的帮助
除了通用之外,您不应该有其他存储库接口IRepository<T>.如果你需要那些,你就会错过抽象.
例如,人们拥有自定义存储库接口的一个常见原因是因为他们有一些存储库具有的自定义查询,而其他存储库没有.例如:
public interface IEmployeeRepository : IRepository<Employee>
{
Employee GetEmployeeOfTheMonth(int month);
}
Run Code Online (Sandbox Code Playgroud)
这里的问题IEmployeeRepository是滥用"自定义查询".自定义查询值得拥有自己的(通用)抽象:
// Defines a query
public interface IQuery<TResult>
{
}
// Defines the handler that will execute queries
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
Run Code Online (Sandbox Code Playgroud)
通过这种抽象,我们可以向系统添加自定义查询,而无需创建IRepository<T>衍生物:
public class GetEmployeeOfTheMonthQuery : IQuery<Employee>
{
[Range(1, 12)]
public int Month { get; set; }
}
class GetEmployeeOfTheMonthHandler : IQueryHandler<GetEmployeeOfTheMonthQuery, Employee>
{
public Employee Handle(GetEmployeeOfTheMonthQuery query)
{
// todo: query the database, web service, disk, what ever.
}
}
Run Code Online (Sandbox Code Playgroud)
需要了解当月员工的消费者现在可以简单地依赖IQueryHandler<GetEmployeeOfTheMonthQuery, Employee>并执行查询,如下所示:
var query = new GetEmployeeOfTheMonthQuery { Month = 11 };
var employee = this.employeeOfMonthHandler.Handle(query);
Run Code Online (Sandbox Code Playgroud)
这似乎是开销,但这个模型非常灵活,可扩展,并且有许多有趣的好处.例如,通过使用装饰器包装处理程序来添加横切关注点非常容易.
这也允许我们的存储库隐藏在一个通用接口后面,这允许我们一次轻松批量注册它们并向它们添加装饰器.
有关更深入的信息,请阅读本文:同时...在我的架构的查询方面.