Generic type inference with multiply-implemented covariant interfaces, how to work around it?
c#, covariance, generics, interface
Solution
Using two F variants (second one just for type inference that calls the other) and an "override" interface J inheriting from I which does nothing it could be done like so:
using System;
using System.Threading;
interface I<out T>
{
void Print();
}
interface J<out T> : I<T> { }
class A : I<C>
{
void I<C>.Print()
{
Console.WriteLine("A: I<C>");
}
}
class B {}
class C : B { }
class D1 : I<A>
{
void I<A>.Print()
{
Console.WriteLine("D1: I<A>");
}
}
class D2 : D1, J<B>
{
void I<B>.Print()
{
Console.WriteLine("D2: I<B>");
}
}
class D3 : D1, J<C>
{
void I<C>.Print()
{
Console.WriteLine("D3: I<C>");
}
}
class D4 : A, J<B>
{
void I<B>.Print()
{
Console.WriteLine("D4: I<B>");
}
}
static class Program
{
static void f<T>(J<T> obj)
{
f((I<T>)obj);
}
static void f<T>(I<T> obj)
{
obj.Print();
}
static void Main()
{
f<A>(new D2());
f(new D2());
f(new D3());
f(new D4());
f<C>(new D4());
Console.ReadKey();
}
}
Output:
D1: I<A>
D2: I<B>
D3: I<C>
D4: I<B>
A: I<C>
Problem
Consider this silly program that does nothing: ``` interface I<out T> { } class A1 : I<A1> { } class A2 : A1, I<A2> { } class B1 { } class B2 : B1, I<B2> { } class C1 : I<A1> { } class C2 : C1, I<A2> { } static class Program { static void f<T>(I<T> obj) { } static void Main() { f<A1>(new A2()); f<A2>(new A2()); f<B1>(new B2()); f<B2>(new B2()); f<A1>(new C2()); f<A2>(new C2()); } } ``` This shows that `A2` and `C2` implement both `I<A1>` and `I<A2>`, and that `B2` implements both `I<B1>` and `I<B2>`. However, modifying this to ``` static void Main() { f(new A2()); f(new B2()); f(new C2()); } ``` shows that on the first and third lines, `f`'s generic type argument cannot be inferred from the passed argument, yet on the second line, it can be. I understand what it is that the compiler is doing here, so that doesn't need explaining. But how can I work around this? Is there some way to modify this so that I can define the interface on both the base and the derived class, yet have type inference work when passing the derived class? What I had in mind was to look for a way to "hide" a base class's implemented interfaces, so that the compiler doesn't see them and use them, even though they do exist. However, C# doesn't seem to provide an option to do so. Clarification: in my silly example program, `A1` implements `I` with itself as the generic type argument. I do have that in my real code, but I also have classes that implement `I` with a different generic type argument, and have added `C1` and `C2` to my example code for that reason.