存储库模式与泛型和DI

时间:2012-10-15 16:38:00

标签: c# generics dependency-injection repository-pattern

我有一个其他合同扩展的基础存储库合同,如下所示

public interface IBaseRepository<T> where T : class 
{
  IList<T> GetContents();
}

然后还有其他合同,如下所示扩展它

public interface IRepository1 : IBaseRepository<MyClass1>
{
}

public interface IRepository2 : IBaseRepository<MyClass2>
{
}

我按如下方式实现IRepository1

public class Repository1 : IRepository1
{
 public IList<MyClass1> GetContents()
 {
  //some code goes here
 }
} 

类似于IRepository2

public class Repository2 : IRepository2
{
 public IList<MyClass2> GetContents()
 {
  //some code goes here
 }
} 

现在我有一个服务Service1,它支持IService,如下所示

public class Service1 : IService
{


}

我想在我的服务构造函数中使用我的基本存储库(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();
   }
  }

这就是我无法做到的。

所以我有一个类型为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()
   }

}

所以它是我想要实现的*标记线,我无法做到。

我正在使用城堡windsor进行DI。

感谢您的帮助

2 个答案:

答案 0 :(得分:8)

除了通用IRepository<T>之外,您不应该有其他存储库接口。如果你需要那些,你就会错过抽象。

例如,人们拥有自定义存储库接口的一个常见原因是因为他们拥有某个存储库具有的自定义查询,而其他存储库没有。例如:

public interface IEmployeeRepository : IRepository<Employee>
{
    Employee GetEmployeeOfTheMonth(int month);
}

这里的问题是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);
}

通过这种抽象,我们可以向系统添加自定义查询,而无需创建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.
    }
}

需要了解当月员工的消费者现在可以简单地依赖IQueryHandler<GetEmployeeOfTheMonthQuery, Employee>并按如下方式执行查询:

var query = new GetEmployeeOfTheMonthQuery { Month = 11 };
var employee = this.employeeOfMonthHandler.Handle(query);

这可能看起来像开销,但这个模型非常灵活,可扩展,并且有许多有趣的好处。例如,通过使用装饰器包装处理程序来添加横切关注点非常容易。

这也允许我们的存储库隐藏在一个通用接口后面,这允许我们一次轻松批量注册它们,并为它们添加装饰器。

有关更深入的信息,请阅读以下文章:Meanwhile… on the query side of my architecture

答案 1 :(得分:0)

不可能。控件容器的反转通过构造函数提供依赖关系,因此它必须在构造函数中知道您想要获得什么类型。所以你应该这样做:

public class service()
{
   private IBaseRepository<MyClass1> _repo;

   public  service(IBaseRepository<MyClass1> repo)
   { 
       _repo = repo;
   } 

   public void MyMethod()
   {

      var x = _repo.MethodFromIBaseRepository()
   }

}