注入通用接口

injecting an generic interface

好的,我对 C# 中的泛型有点迷茫

我有这个通用界面

interface IInvoiceStorage<T>
    where T : class
{
    void Persist(T Invoice);
}

有两个 classes 实现接口

public class FacturaStorageForSQLServer:IInvoiceStorage<EVT>
{
      public void Persist(EVT Invoice)
      {
        /*Implementation*/
      }
}



public class FacturaStorageForMySQLServer:IInvoiceStorage<EVTFruit>
{
      public void Persist(EVTFruit Invoice)
      {
         /*Implementation*/
      }
}

当我想在我的服务中声明这个时,问题就来了class

public class invoice_service
{
   IInvoiceStorage Storage;
   public invoice_service(IInvoiceStorage storage)
   {
     Storage=_storage;
   }
}

C# 告诉我必须声明接口的 de 类型,但如果我这样做,那么我的服务 class 将依赖于实现而不是接口。

建议??

更新 1: 抱歉,如果我声明接口将仅依赖于使用该类型的实现的类型,但是如果我有两个使用两种不同类型(例如 EVT 和 EVTFruit)的实现会发生什么。

我正在考虑使用另一个接口在 EVT 和 EVTFruit 之间建立关系,但它们可能是两个完全不同的对象,所以我不确定这是否是个好主意。

你可以稍微改变一下你的class:

public class invoice_service<T> where T : class
{
   IInvoiceStorage<T> Storage;
   public invoice_service(IInvoiceStorage<T> storage)
   {
     Storage=_storage;
   }
}

这将使您能够正确使用界面并保持其通用性。

根据您的需要,您还可以定义该接口的非通用版本:

public interface IInvoiceStorage
{
  ...
}

并使 classes 也继承自该接口。

public class FacturaStorageForSQLServer : IInvoiceStorage, IInvoiceStorage<EVT>
public class FacturaStorageForMySQLServer : IInvoiceStorage, IInvoiceStorage<EVTFruit>

这样您就可以在 invoice_service class.

中使用非通用版本的界面

但是,正如我所说,如果您可以使该接口的功能独立于类型(例如,List<T> 还实现了 IList 列表功能,则没有类型),这取决于您的需要。

在尝试了您的建议并阅读了这里的一些博客之后,这就是我所做的,并且至少目前正在满足我的要求。当我意识到我不应该将通用存储库模式用作存储库本身,而是作为存储库的助手时,问题就解决了!最后,我所做的是将通用接口包装在另一层非通用接口中。

服务class 调用 IInvoiceRepositoryService 实现

public class InvoiceService
{
   private IInvoiceRepositoryService RepositoryService;
   public SQLInvoiceService(IInvoiceRepositoryService _RS)
   {
       RepositoryService=_RS;
   }
}

及其对 EVT 和 EVTFruit 的各自实现。

public class EVTRepository:IInvoiceRepositoryService
{
  private IInvoiceStorage<EVT> EVTStorage;

  public EVTInvoiceRepository(IInvoice<EVT> _EVT)
  {
    EVTStorage=_EVT;
  }
}


public class EVTStorageForSQLServer: IInvoiceStorage<EVT>
{
   /*Implementation*/
}

public class EVTStorageForMySQLServer: IInvoiceStorage<EVT>
{
   /*Implementation*/
}



public class EVTFruitRepository:IInvoiceRepositoryService
{
  private IInvoiceStorage<EVT> EVTFruitStorage;

  public EVTFruitInvoiceRepository(IInvoice<EVTFruit> _EVTFruit)
  {
    EVTFruitStorage=_EVTFruit;
  }
}

public class EVTFruitStorageForSQLServer: IInvoiceStorage<EVTFruit>
{
   /*Implementation*/
}

public class EVTFruitStorageForMySQLServer: IInvoiceStorage<EVTFruit>
{
   /*Implementation*/
}

最后我认为这只是一个设计问题。我将把 Ron Beyer 的回复标记为答案,因为它有效而且非常简单