Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern for exposing non-generic version of generic interface

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

like image 586
fearofawhackplanet Avatar asked Jul 08 '11 10:07

fearofawhackplanet


People also ask

Can a non generic class implement a generic interface?

It is possible to create a non-generic class that implements a generic interface, provided that the type parameters are provided.

Can we have non generic method in generic class C#?

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.

Can a generic type be an interface?

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.

When would you use a generic interface?

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.


1 Answers

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.

like image 54
Marc Gravell Avatar answered Sep 28 '22 04:09

Marc Gravell