c# - Inherited Generic Type Unification -


for scenario such this:

public interface ianimal {  }  public interface igiraffe : ianimal {  }  public interface iquestionablecollection : ienumerable<ianimal> {     void someaction(); }  public interface iquestionablecollection<out t> : iquestionablecollection, ienumerable<t>     t : ianimal {  }  public class questionablecollection<t> : iquestionablecollection<t>     t:ianimal {     // implementation...  } 

the complier generate error:

'iquestionablecollection<t>' cannot implement both 'system.collections.generic.ienumerable<ianimal>' , 'system.collections.generic.ienumerable<t>' because may unify type parameter substitutions 

and makes sense, there indeed ambiguity between 2 interfaces c# can't resolve unless uses type constraint, doesn't per language spec @ericlippert explains here.

my question how should implement same effect here?

it seems should able express collection enumerable base interface. (i'd provide set of methods utilized without knowing concrete type, make apis/reflection code cleaner, i'd keep base collection non-generic if @ possible. otherwise, there no need 2 interfaces.)

the implementation can think of compiles like:

public interface iquestionablecollectionbase {     void someaction(); }  public interface iquestionablecollection : iquestionablecollectionbase, ienumerable<ianimal> {  }  public interface iquestionablecollection<out t> : iquestionablecollectionbase, ienumerable<t>     t : ianimal {  }  public class questionablecollectionbase<t> : iquestionablecollection     t : ianimal {     protected list<t> _items = new list<t>();      public void someaction() { }      ienumerator ienumerable.getenumerator() { return ((ienumerable)_items).getenumerator(); }     ienumerator<ianimal> ienumerable<ianimal>.getenumerator() { return ((ienumerable<ianimal>)_items).getenumerator(); } }  public class questionablecollection<t> : questionablecollectionbase<t>, iquestionablecollection<t>     t : ianimal {     public ienumerator<t> getenumerator() { return ((ienumerable<t>)_items).getenumerator(); } } 

note i've had move methods i'd use on both interfaces base method , have 2 levels of implementation class - seems i'm jumping through enough hoops here i've got missing something...

how should implemented?

the simplest workaround change ienumerables "is-a" "has-a", this:

public interface ianimal { } public interface igiraffe : ianimal { }  public interface iquestionablecollection {     ienumerable<ianimal> animals { get; }     void someaction(); }  public interface iquestionablecollection<out t> : iquestionablecollection     t : ianimal {     new ienumerable<t> animals { get; } }  public class questionablecollection<t> : iquestionablecollection<t>     t : ianimal, new() {     private readonly list<t> list = new list<t>();      public ienumerable<t> animals     {         { return list; }     }      ienumerable<ianimal> iquestionablecollection.animals     {         { return (ienumerable<ianimal>)list; }     }      public void someaction()     {         list.add(new t());     } }  class giraffe : igiraffe { }  [testmethod] public void test() {     var c = new questionablecollection<giraffe>();     iquestionablecollection<giraffe> = c;     iquestionablecollection<igiraffe> i2 = i;      assert.areequal(0, c.animals.count());     assert.areequal(0, i.animals.count());     c.someaction();     i.someaction();     assert.areequal(2, c.animals.count());     assert.areequal(2, i.animals.count()); } 

note can avoid cast in questionablecollection<t> if add where t : class constraint.