【问题标题】:Implementing generic interface with generic method用泛型方法实现泛型接口
【发布时间】:2018-12-14 10:24:49
【问题描述】:

我的界面如下:

public interface IService<T> where T : class
{
    Task<IEnumerable<T>> GetAsync<U>(int subscriberId, U request) where U : SearchRequestBase;
}

我正在实现以下方式(CategoriesRequest 继承 SearchRequestBase):

public async Task<IEnumerable<CategoriesResponse>> GetAsync<CategoriesRequest>(int subscriberId, CategoriesRequest request)
{
    // Implementation
}

但是无论我做什么,我都会遇到编译错误,使其工作的唯一方法是将 U 泛型放在接口中并在那里放置约束。

这是推荐的方法吗?或者我可以在我的方法旁边声明带有约束的泛型方法并以这种方式实现吗?

我的意图是将泛型仅作为返回类型,并且我的输入必须包含从 SearchRequestBase 继承的任何内容。

更新

这是我的基类:

public class SearchRequestBase
{
    private const int minimumQueryLength = 3;
    private const int minimumResultsSize = 1;
    private const int maximumResultsSize = 100;
    private const int defaultResultsSize = 5;

    protected SearchRequestBase()
    {
    }

    [Required]
    [MinLength(minimumQueryLength, ErrorMessage = "Query string has to contain at least three characters")]
    public string Query { get; set; }

    [Range(minimumResultsSize, maximumResultsSize, ErrorMessage = "Size must be between 1 and 100")]
    public int Size { get; set; } = defaultResultsSize;
}

还有CategoriesRequest 类现在还没有实现任何额外的属性(但会)。

public class CategoriesRequest : SearchRequestBase
{
}

还有更多的请求继承自 SearchRequestBase。

所以现在有我的IService 界面:

public interface IService<T> where T : class
{
    Task<IEnumerable<T>> GetAsync(int subscriberId, SearchRequestBase request);
}

我在CategoryService

public class CategoryService : IService<CategoriesResponse>
{
    private readonly IElasticClient _client;

    public CategoryService(IElasticClient client)
    {
        _client = client ?? throw new ArgumentNullException(nameof(client));
    }

    public async Task<IEnumerable<CategoriesResponse>> GetAsync(int subscriberId, CategoriesRequest request)
    {
        var descriptor = new CategoryBuilder().Build(subscriberId, request);

        var index = "categories";

        var response = await _client.SearchAsync<CategoriesResponse>(descriptor.Index(index));

        return response.Documents;
    }
}

但是编译器诅咒我并给出以下错误:

Error   CS0535  'CategoryService' does not implement interface member 'IService<CategoriesResponse>.GetAsync(int, SearchRequestBase)'

【问题讨论】:

  • 泛型接口拥有额外泛型的方法(声明额外的类型参数)很少是正确的(根据我的经验)。在您的示例中,您期望一个类能够承诺为继承自 SearchRequestBaseany 类型返回 CategoriesResponse?因为这就是您的接口定义似乎暗示的内容。
  • 你能提供更多的上下文吗?查看包含您的实现的类的声明会有所帮助。
  • 另外,您使用CategoriesRequest 作为泛型类型名称,这可能也会让您感到困惑。
  • 如果U 应该是SearchRequestBase 类型,那么为什么不是Task&lt;IEnumerable&lt;T&gt;&gt; GetAsync(int subscriberId, SearchRequestBase request)
  • 所以你可能想要的是:public interface IService&lt;T, U&gt; where T : class where U : SearchRequestBase { Task&lt;IEnumerable&lt;T&gt;&gt; GetAsync(int subscriberId, U request); }

标签: c# generics


【解决方案1】:

您的方法签名需要:

public async Task<IEnumerable<CategoriesResponse>> GetAsync(
    int subscriberId, SearchRequestBase request)

否则你需要在接口中添加另一个泛型类型参数。例如:

public interface IService<TRequest, TResponse>
    where TRequest : SearchRequestBase
    where TResponse : class
{
    Task<IEnumerable<TResponse>> GetAsync(int subscriberId, TRequest request);
}

【讨论】:

  • 我也是这么想的。谢谢大卫
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-14
  • 2018-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多