创建使用通用参数的通用服务接口



我正在尝试使用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();
}

最新更新