Given the following covariant common interface
public interface IContainer<out T> { T Value { get; } }
We can create a class that implements this interface several times for several types. In the scenario we are interested in, these common types have a common base type.
public interface IPrint { void Print(); } public class PrintA : IPrint { public void Print() { Console.WriteLine("A"); } } public class PrintB : IPrint { public void Print() { Console.WriteLine("B"); } } public class SuperContainer : IContainer<PrintA>, IContainer<PrintB> { PrintA IContainer<PrintA>.Value => new PrintA(); PrintB IContainer<PrintB>.Value => new PrintB(); }
Now everything becomes more interesting when using this class using a link like IContainer<IPrint> .
public static void Main(string[] args) { IContainer<IPrint> container = new SuperContainer(); container.Value.Print(); }
It compiles and runs without problems and prints "A". What I found in spec :
The implementation of a specific IM interface, where I am the interface in which the member M is declared, is determined by studying each class or structure S, starting with C and repeating for each subsequent base class C, until a match is found:
- If S contains an declaration of an explicit implementation of an interface member that matches I and M, then this member is an IM implementation
- Otherwise, if S contains a declaration of a non-static public member that matches M, then this member is an implementation of IM
The first marker point seems relevant because the interface implementations are explicit. However, he does not say anything about which implementation is selected when there are several candidates.
This becomes even more interesting if we use public poperty to implement IContainer<PrintA> :
public class SuperContainer : IContainer<PrintA>, IContainer<PrintB> { public PrintA Value => new PrintA(); PrintB IContainer<PrintB>.Value => new PrintB(); }
Now, according to the spec above, because there is an explicit interface implementation via IContainer<PrintB> , I expect this to print "B". However, the public property and the seal βAβ are used instead.
Similarly, if instead I implement IContainer<PrintA> explicitly and IContainer<PrintB> through a public property, it still prints βAβ.
It appears that only the order in which the interfaces are declared depends on the output. If I change the announcement to
public class SuperContainer : IContainer<PrintB>, IContainer<PrintA>
everything prints "B"!
What part of the specification defines this behavior, if it is correctly defined at all?