注入通用接口
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 的回复标记为答案,因为它有效而且非常简单
好的,我对 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 的回复标记为答案,因为它有效而且非常简单