【问题标题】:Creating a generic service interface that uses generic params创建使用通用参数的通用服务接口
【发布时间】:2020-04-20 11:05:13
【问题描述】:

我正在尝试使用 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 定义的。

有没有什么方法可以只用两个参数创建该接口,以免重复已经定义的类型?

【问题讨论】:

  • 如果我错了,请纠正我,但如果接口已经在抽象类中处理,你不能省略 V 部分。

标签: c# generics interface


【解决方案1】:

您可以稍微更改您的代码,将ListingDTO&lt;T&gt; 转换为接口并使泛型类型参数T 协变。在这种情况下,您还应该将Items 类型更改为IEnumerable&lt;T&gt;,因为List&lt;T&gt; 是不变的。

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&lt;out T&gt; 的协变声明允许您在服务实现中使用HListing(实现此接口)

【讨论】:

  • @ganchito55 对您有帮助吗?您需要更多详细信息或信息吗?
  • 感谢您的回答和解释,我使用您的回答来开发我的解决方案。这个答案的问题在于,在很多情况下IListingDTO 的实现是相等的,所以我认为使用基类是正确的方法
【解决方案2】:

这可能会稍微改变您的设计,但我会尝试将以下代码替换为不带类型参数的代码。 这样我们就可以将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();
}

【讨论】:

  • 这个实现的问题在于,将 HListing 与 ListingItemBase 类型的项目一起使用会迫使您强制转换,因为每个具体的项目类都有不同的属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2022-11-18
  • 2023-03-07
  • 2021-06-22
  • 1970-01-01
相关资源
最近更新 更多