Search code examples
c#genericsinterfaceienumerableimplementation

Implement an interface method that gets IEnumerable of interface or of base class as parameter


[Surely a similar question was asked before multiple times, but somehow I couldn't find a good duplicate, so opening this one]

Generally:

Is it possible to implement an interface method, that gets IEnumerable of either interface or of base-class as type-parameter, where the implementing method IEnumerable uses a type-parameter of a class that implements the interface\derives from the base class?

More concretely:

  • We have either:
    1. Some interface type interface IZ with some implementing classes:
      • class CZ1: IZ
      • class CZ2: IZ
    2. Some base-class type class CZ with some derived classes:
      • class CZ1: CZ
      • class CZ2: CZ
  • interface IA defines a method with a parameter of either:
    • IEnumerable<IZ>, or:
    • IEnumerable<CZ>.
  • class CA1 : IA wishes to implement the interface's method with IEnumerable<CZ1>, while class CA2 :IA wishes to implement the interface's method with IEnumerable<CZ2>.

An implementation like this throws an error:

<class> does not implement interface member <method with IEnumerable of interface\base-class>

  • What is a possible way to make this kind of implementation compile?
  • Would using generic-type parameters with constraints help in any way?
  • If there is no built-in way to make it work in a direct way, is there a good "design pattern" to make implementation in this "spirit" work?

Full example:

Types to be used as the IEnumerable type-parameter (using IZ here, but CZ should behave the same way):

interface IZ {}
class CZ1 : IZ {}
class CZ2 : IZ {}

Types that try to use the type parameters:

interface IA
{
    void Set(IEnumerable<IZ> records)
}

class CA1 : IA 
{
    public void Set(IEnumerable<CZ1> records) {}  <-- compile error
}

class CA2 : IA
{
    public void Set(IEnumerable<CZ2> records) {}  <-- compile error
}

Solution

  • Like this?

    interface IZ { }
    class CZ1 : IZ { }
    class CZ2 : IZ { }
    
    interface IA<T> where T : IZ
    {
        void Set(IEnumerable<T> records);
    }
    
    class CA1 : IA<CZ1>
    {
        public void Set(IEnumerable<CZ1> records) { }
    }
    class CA2 : IA<CZ2>
    {
        public void Set(IEnumerable<CZ2> records) { }
    }