我正在尝试使用c#泛型来创建一个通用接口,该接口可以作为构建所有列表服务的基础。然而,我对这个定义有一个问题。
基类
abstract class ListingParams { }
abstract class ListingDTO<T> where T : ListingItemDTO
{
public List<T> Items{ get; set; }
}
abstract class ListingItemDTO { }
一个具体的例子
class HListingParams : ListingParams { }
class HListing : ListingDTO<HItem> { }
class HItem : ListingItemDTO { }
接口
interface IListingToolsService<in TFilter, out U, V>
where TFilter : ListingParams
where U : ListingDTO<V> where V : ListingItemDTO
{
int Count(TFilter parameters);
U Get(TFilter parameters);
}
问题从这里开始,由于Get方法返回泛型类型,我必须向接口添加第三个泛型参数
如果我想创建该接口的具体实现,我必须创建这样的东西:
class HListingToolsService : IListingToolsService<ListingParams, HListing, HItem>
{
public int Count(ListingParams parameters) => throw new NotImplementedException();
public HListing Get(ListingParams parameters) => throw new NotImplementedException();
}
然而,根据定义,HListing
不是通用的,因为它是使用HItem
定义的。
是否有任何方法可以只使用两个参数创建接口,以避免重复已经定义的类型
您可以稍微更改代码,将ListingDTO<T>
转换为接口,并使泛型类型参数T
协变。在这种情况下,您还应该将Items
类型更改为IEnumerable<T>
,因为List<T>
是不变的。
interface IListingDTO<out T> where T : ListingItemDTO
{
public IEnumerable<T> Items { get; }
}
然后在HListing
类中实现
class HListing : IListingDTO<HItem>
{
public IEnumerable<HItem> Items { get; }
}
之后,您可以更新IListingToolsService
接口,并摆脱V
泛型类型参数及其约束
interface IListingToolsService<in TFilter, out U>
where TFilter : ListingParams
where U : IListingDTO<ListingItemDTO>
{
int Count(TFilter parameters);
U Get(TFilter parameters);
}
最后实现HListingToolsService
类
class HListingToolsService : IListingToolsService<ListingParams, HListing>
{
public int Count(ListingParams parameters) => throw new NotImplementedException();
public HListing Get(ListingParams parameters) => throw new NotImplementedException();
}
IListingDTO<out T>
的协变声明允许您在服务实现中使用HListing
(实现该接口(
这可能会稍微改变您的设计,但我会尝试用不带类型参数的代码替换以下代码。通过这种方式,我们可以将ListingDTO封装到一个不直接接受类型参数的类中。
abstract class ListingItemBase : ListingItemDTO { }
abstract class ListingDTOBase : ListingDTO<ListingItemBase>
{
public List<ListingItemBase> Items { get; set; }
}
并使HListing继承ListingDTOBase:
class HListing : ListingDTOBase { }
之后,您应该能够在不使用V类型参数的情况下定义接口:
interface IListingToolsService<in TFilter, out U>
where TFilter : ListingParams
where U : ListingDTOBase
{
int Count(TFilter parameters);
U Get(TFilter parameters);
}
和服务:
class HListingToolsService : IListingToolsService<ListingParams, HListing>
{
public int Count(ListingParams parameters) => throw new NotImplementedException();
public HListing Get(ListingParams parameters) => throw new NotImplementedException();
}