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
It is possible to create a non-generic class that implements a generic interface, provided that the type parameters are provided.
Yes, There are two level where you can apply generic type . You can apply generic type on Method level as well as Class level (both are optional). As above example you applied generic type at method level so, you must apply generic on method return type and method name as well. You need to change a bit of code.
Java Generic Classes and SubtypingWe can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.
It's often useful to define interfaces either for generic collection classes, or for the generic classes that represent items in the collection. To avoid boxing and unboxing operations on value types, it's better to use generic interfaces, such as IComparable<T>, on generic classes.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With