用于公开通用接口的非泛型版本的模式

fea*_*net 26 c# generics design-patterns interface open-generics

假设我有以下界面来公开分页列表

public interface IPagedList<T>
{
    IEnumerable<T> PageResults { get; }
    int CurrentPageIndex { get; }
    int TotalRecordCount { get; }
    int TotalPageCount { get; }        
    int PageSize { get; }
}   
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

分页控件不感兴趣T(列表的实际内容).它只需要页面数,当前页面等.所以唯一的原因PagedListPager是泛型是这样它将使用通用IPagedList<T>参数进行编译.

这是代码味吗?我是否应该关心我有效地使用冗余通用?

在这种情况下是否有标准模式用于公开接口的其他非泛型版本,因此我可以删除寻呼机上的泛型类型?

public class PagedListPager(IPagedList list)
Run Code Online (Sandbox Code Playgroud)

编辑

我想我也会添加当前解决这个问题的方法并邀请评论是否是一个合适的解决方案:

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
}
Run Code Online (Sandbox Code Playgroud)

现在我可以传递ConcretePagedList<T>给非泛型类/函数

Mar*_*ell 29

我的方法是使用new重新声明PageResults,并将其暴露TType:

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; }
}  
Run Code Online (Sandbox Code Playgroud)

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

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); }
    }
}
Run Code Online (Sandbox Code Playgroud)

此方法通过通用API和非通用API使API完全可用.


Ank*_*kur 7

一种选择是创建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; }
    }
Run Code Online (Sandbox Code Playgroud)

然后你的控制:

public class PagedListPager(IPagedListDetails details)
Run Code Online (Sandbox Code Playgroud)

  • @fearofawhackplanet:IMHO接口继承被大量使用不足.恕我直言,类似IList的东西应该来自IReadableByIndex,IMutableByIndex,IAppendable和IRemovableByIndex; 数组应该已经实现了前两个但不是最后两个. (2认同)

arc*_*hil 5

首先定义两个接口

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

public interface IPagedList<T> : IPageSpecification
{
    IEnumerable<T> PageResults { get; }
}   
Run Code Online (Sandbox Code Playgroud)

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