Say I have the following interface for exposing a paged list
public interface IPagedList<T>
{
IEnumerable<T> PageResults { get; }
int CurrentPageIndex { get; }
int TotalRecordCount { get; }
int TotalPageCount { get; }
int PageSize { get; }
}
Now I want to create a paging control
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);
}
}
The paging control has no interest in T
(the actual contents of the list). It only requires the number of pages, current page etc. So the only reason PagedListPager
is generic is so that it will compile with the generic IPagedList<T>
paramater.
Is this a code smell? Should I care that I effectively have a redundant generic?
Is there a standard pattern in a case like this for exposing an additional non-generic version of the interface, so I can remove the generic type on the pager?
public class PagedListPager(IPagedList list)
Edit
I thought I'd also add the current way I've solved this problem and invite comments on whether it's a suitable solution:
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
}
Now I can pass ConcretePagedList<T>
to non-generic classes/functions
My approach here would be to use new
to re-declare the PageResults
, and expose the T
as a 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; }
}
This will, however, require "explicit interface implementation", i.e.
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); }
}
}
This approach makes the API fully usable via both the generic and non-generic API.