【问题标题】:c# 7 when using generics for method parameter I get The constraints for type parameter 'U' of method must match the constraints for the interfacec# 7 when using generics for method parameter I get The constraints for type parameter 'U' of method must match the constraints for the interface
【发布时间】:2018-01-23 22:14:06
【问题描述】:

我正在尝试创建一个接口和一个具体实现,其中接口是泛型类型并且其中一个方法具有泛型参数。

我想保留 GetPagedList 方法参数,resourceParams,通用,以便我可以为接口的不同实现传递不同的 resourceParams 对象。

当使用下面显示的代码时,我得到了错误;

方法“ShippingServicesRepository.GetPagedList(U)”的类型参数“U”的约束必须匹配接口方法 IBaseRepository.GetPagedList(U) 的类型参数“U”的约束。考虑改用显式接口实现

这是我的界面;

public interface IBaseRepository<T> 
{
    bool Save();
    bool Exists(int recordId);
    bool MarkForDeletion(int recordId);
    PagedList<T> GetPagedList<U>(U resourceParams) where U : class;
    T Get(int id);
    void Add(T record);
    void Update(T record);
}

这是我的实现;

public class ShippingServicesRepository<T> : IBaseRepository<T> 
{

    //                      /--- GetPagedList is what is throwing the error
    //                      |
    public PagedList<T> GetPagedList<U> (U resourceParams) where U : ShippingServicesResourceParameters
    {
        try
        {

            var collectionBeforePaging =
                _manifestContext.ShippingServices
                .ApplySort(resourceParams.OrderBy, _propertyMappingService.GetPropertyMapping<ShippingServicesDto, ShippingServices>());
            if (!string.IsNullOrEmpty(resourceParams.SearchQuery))
            {
                var searchQueryForWhereClause = resourceParams.SearchQuery.Trim().ToLowerInvariant();
                collectionBeforePaging = collectionBeforePaging
                    .Where(a => a.ReferenceId.ToLowerInvariant().Contains(searchQueryForWhereClause));
            }
            collectionBeforePaging = collectionBeforePaging
                .Where(d => d.DeleteFlag == resourceParams.DeleteFlag);

            return (dynamic)PagedList<ShippingServices>.Create(collectionBeforePaging,
                resourceParams.PageNumber,
                resourceParams.PageSize);
        }
        catch (Exception)
        {
            _logger.LogError(500, "ShippingServices Filter [{FILTER}]", resourceParams);
            throw;
        }
    }

    public void Add(T record)
    {
        ...
    }

    public bool Exists(int recordId)
    {
        ...
    }

    public T Get(int id)
    {
        ...
    }

    public bool MarkForDeletion(int recordId)
    {
        ...
    }

    public bool Save()
    {
        ...
    }

    public void Update(T record)
    {
        ...
    }

}

这是我的 ShippingServicesResourceParameters 类

public class ShippingServicesResourceParameters : BaseResourceParameters
{
    public string FileName { get; set; }
}

这里是 ShippingServicesResourceParameters 继承的 BaseResourceParameters 类

public class BaseResourceParameters
{
    private int _pageSize;
    public int PageNumber { get; set; } = 1;
    public int PageSize
    {
        get
        {
            return _pageSize;
        }
        set
        {
            _pageSize = (value > MaxPageSize) ? MaxPageSize : value;
            if (value == 0)
            {
                _pageSize = 10; // set a default size
            }
        }
    }

    public int MaxPageSize { get; set; } = 20;
    public bool DeleteFlag { get; set; }
    public string SearchQuery { get; set; }
    public string OrderBy { get; set; } = "Id";
    public string Fields { get; set; }
}

如果我没有在具体实现中的方法签名和接口中的“where U:class”中添加“where U: ShippingServicesResourceParameters”,我得到一个“无法从方法组转换为字符串...”在具体实现中第一次使用 resourceParams 变量时出错。 (在“.ApplySort(resourceParams.OrderBy”)

我在这里错过了什么?

【问题讨论】:

  • 在方法中使用具体类时所有泛型的任何原因?
  • @MikePerrenoud 你不能用另一个类约束来指定类。
  • 请制作一个大约是该复制品大小的二十分之一的复制品。这里有大量完全不相关的垃圾。
  • 错误信息告诉你问题到底出在哪里。您正在编写的方法有哪些限制?您希望它实现的接口实现的约束是什么?他们是一样的吗? (提示,它们不是,错误消息告诉你的也是。)
  • 不要随意更改约束条件,希望它们能解决问题。这不是一个可靠的工程方法。 首先了解问题,然后然后解决它。

标签: c# generics interface .net-core asp.net-core-mvc-2.0


【解决方案1】:

让我们首先做你应该做的事情,并制作一个演示问题的最小程序:

interface I 
{
    void M<U>(U u) where U : class;
}
class D 
{
    public void O() {}
}
class C : I
{
    public void M<U>(U u) where U : D
    {
        u.O();
    }
}

这是一个错误,因为 C 没有实现 I。它没有实现 I,因为:

I i = new C();
i.M<Giraffe>(new Giraffe());

现在我们有一个长颈鹿传递给C.M&lt;Giraffe&gt;(Giraffe),但C.M&lt;U&gt; 要求U 是D。所以这是非法的。

我们不能这样修复它:

    public void M<U>(U u) where U : class
    {
        u.O();
    }

因为现在我们可以在 Giraffe 类型的接收器上调用 D.O()

因此我们必须像这样修复它:

interface I 
{
    void M<U>(U u) where U : D;
}
class D 
{
    public void O() {}
}
class C : I
{
    public void M<U>(U u) where U : D
    {
        u.O();
    }
}

现在我们都很好。

需要使实现约束与接口约束相匹配,就像您需要满足接口施加的所有其他要求一样。 接口是合同。你必须履行你的讨价还价。

我注意到这就是错误消息所说的:你必须匹配约束,而你没有这样做。注意错误信息;大多数时候他们会告诉你哪里出了问题。

【讨论】:

  • 感谢您的解释,感谢您花时间制定答案。
  • @EiEiGuy:不客气。如果还不清楚,请这样考虑。假设你有interface I { void M(Animal a); },那么你不能说,哦,嘿,我想实现I,但M 只接受GiraffeI 的合约是 M 可以接受任何Animal,如果你想实现I,这是一个要求。在您的情况下,您对该方法的要求是 U 可以使用任何引用类型构造。然后你不能说“好吧,在 my 实现中,U 只能用 ShippingServicesResourceParameters 后代类型构造,出于同样的原因。
猜你喜欢
  • 2020-03-05
  • 2022-12-19
  • 2015-05-30
  • 1970-01-01
  • 2022-12-01
  • 2022-12-27
  • 2022-06-16
  • 1970-01-01
  • 2021-10-06
相关资源
最近更新 更多