暴露非泛型接口的非泛型版本的模式

Posted

技术标签:

【中文标题】暴露非泛型接口的非泛型版本的模式【英文标题】:Pattern for exposing non-generic version of generic interface 【发布时间】:2011-10-01 04:17:47 【问题描述】:

假设我有以下用于公开分页列表的界面

public interface IPagedList<T>

    IEnumerable<T> PageResults  get; 
    int CurrentPageIndex  get; 
    int TotalRecordCount  get; 
    int TotalPageCount  get;         
    int PageSize  get; 
   

现在我想创建一个分页控件

public class PagedListPager<T>

    public PagedListPager<T>(IPagedList<T> list)
    
        _list = list;
    

    public void RenderPager()
    
        for (int i = 1; i < list.TotalPageCount; i++)
            RenderLink(i);
    

分页控件对T(列表的实际内容)没有兴趣。它只需要页数、当前页等。所以PagedListPager 是通用的唯一原因是它可以使用通用IPagedList&lt;T&gt; 参数进行编译。

这是代码异味吗?我应该关心我实际上有一个多余的泛型吗?

在这种情况下,是否有标准模式可以公开额外的非泛型接口版本,以便我可以删除寻呼机上的泛型类型?

public class PagedListPager(IPagedList list)

编辑

我想我也会添加我解决此问题的当前方式,并邀请 cmets 了解它是否是合适的解决方案:

public interface IPagedList // non-generic version

    IEnumerable<object> PageResults  get; 
    int CurrentPageIndex  get; 
    int TotalRecordCount  get; 
    int TotalPageCount  get;         
    int PageSize  get; 



public class ConcretePagedList<T> : IPagedList<T>, IPagedList

    #region IPagedList<T> Members

    public IEnumerable<T> PageResults  get; set; 
    public int CurrentPageIndex  get; set; 
    public int TotalRecordCount  get; set; 
    public int PageSize  get; set; 

    #endregion

    #region IPagedList Members

    IEnumerable<object> IPagedList.PageResults
    
        get  return PageResults.Cast<object>(); 
    

    #endregion

现在我可以将ConcretePagedList&lt;T&gt; 传递给非泛型类/函数

【问题讨论】:

PagedListPager&lt;T&gt; 是类还是方法声明? @Gregg 抱歉,我会编辑它。 我不喜欢在两个接口中定义属性,因为你可以显式地实现它们来做不同的事情。例如, IPagedList.PageSize getreturn 8; IPageList.PageSizegetreturn this.PageResults.Count(); 您拥有第二个界面的唯一原因是提供强类型,所以 Marc 的回答似乎消除了类对不应不同的属性产生不同结果的能力。 【参考方案1】:

我在这里的方法是使用new 重新声明PageResults,并将T 公开为Type

public interface IPagedList

    int CurrentPageIndex  get; 
    int TotalRecordCount  get; 
    int TotalPageCount  get;         
    int PageSize  get; 

    Type ElementType  get; 
    IEnumerable PageResults  get; 
   

public interface IPagedList<T> : IPagedList

    new IEnumerable<T> PageResults  get; 
  

然而,这将需要“显式接口实现”,即

class Foo : IPagedList<Bar>

    /* skipped : IPagedList<Bar> implementation */

    IEnumerable IPagedList.PageResults 
        get  return this.PageResults;  // re-use generic version
    
    Type IPagedList.ElementType 
        get  return typeof(Bar); 
    

这种方法使 API 可以通过通用和非通用 API 完全可用。

【讨论】:

谢谢 Marc,我喜欢这个,它与我想出的非常相似,但实现更简洁。 @Moop 取决于签名的变化方式。你有具体的例子吗? @MarcGravell 这样的事情:public interface IBag IFruit GetNextObject(); public interface IBag&lt;T&gt; where T : IFruit new T GetNextObject();【参考方案2】:

一种选择是创建 2 个接口,这样:

    public interface IPagedListDetails
    
        int CurrentPageIndex  get; 
        int TotalRecordCount  get; 
        int TotalPageCount  get; 
        int PageSize  get; 
    

    public interface IPagedList<T> : IPagedListDetails
    
        IEnumerable<T> PageResults  get; 
    

然后你的控制:

public class PagedListPager(IPagedListDetails details)

【讨论】:

我曾考虑过这一点,但觉得接口继承通常不是一个好主意? 接口继承没有问题,如果你看看.NET BCL你会发现有各种泛型接口继承自非泛型类 @fearofawhackplanet:恕我直言,接口继承未得到充分利用。恕我直言,像 IList 这样的东西应该派生自 IReadableByIndex、IMutableByIndex、IAppendable 和 IRemovableByIndex;数组应该实现了前两个而不是后两个。【参考方案3】:

定义两个接口,先

    public interface IPageSpecification
    
        int CurrentPageIndex  get; 
        int TotalRecordCount  get; 
        int TotalPageCount  get;         
        int PageSize  get; 
       

public interface IPagedList<T> : IPageSpecification

    IEnumerable<T> PageResults  get; 
   

如您所见,IPagedList 派生自 IPageSpecification。在您的方法中,仅使用 IPageSpecification 作为参数。在其他情况下,IPagedList - IPagedList 的实现者也将包含来自 IPageSpecification 的数据

【讨论】:

以上是关于暴露非泛型接口的非泛型版本的模式的主要内容,如果未能解决你的问题,请参考以下文章

LINQ学习系列-----3.1 查询非泛型集合

ObjectDataSource 未能找到带参数的非泛型方法

ObjectDataSource 'odsX' 找不到没有参数的非泛型方法 'methodX'

返回类型为协议的泛型函数与参数和返回类型为协议的非泛型函数的区别

ObjectDataSource 找不到采用类型参数的非泛型方法

InvalidOperationException:ObjectDataSource 找不到具有参数的非泛型方法: