代码之家  ›  专栏  ›  技术社区  ›  EiEiGuy

c#7当对方法参数使用泛型时,我得到方法的类型参数“U”的约束必须与接口的约束匹配

  •  -2
  • EiEiGuy  · 技术社区  · 7 年前

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

    我希望保持GetPagedList方法参数resourceParams为泛型,以便为接口的不同实现传入不同的resourceParams对象。

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

    方法“ShippingServicesRepository”的类型参数“U”的约束。GetPagedList(U)“”必须与接口方法IBaseRepository的类型参数“U”的约束匹配。GetPagedList(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:ShippingServicesResourceParameters”和在接口中添加“where U:class”,我会得到一个“无法从方法组转换为字符串…”在具体实现中首次使用resourceParams变量时出错。(位于“.ApplySort(resourceParams.OrderBy”)

    我错过了什么?

    1 回复  |  直到 6 年前
        1
  •  7
  •   Eric Lippert    7 年前

    我们开始吧 你首先应该做什么 并制作一个演示问题的最小程序:

    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<Giraffe>(Giraffe) 但是 C.M<U> 要求U是D,所以这是非法的。

    我们无法像这样修复它:

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

    因为现在我们可以 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();
        }
    }
    

    现在我们都好了。

    你是 必修的 使实现约束与接口约束匹配,就像您需要满足接口强加的所有其他需求一样。 接口是合同 . 你必须完成你的交易。

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