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 thePageResults
, and expose theT
as aType
:This will, however, require "explicit interface implementation", i.e.
This approach makes the API fully usable via both the generic and non-generic API.
One option is to create 2 interfaces such that:
And then your control:
Define two interfaces, first
As you see, IPagedList is derived from IPageSpecification. In your method, only use IPageSpecification as parameter. In other cases, IPagedList - implementers of IPagedList would also contain data from IPageSpecification