Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Explicit Interfaces with inheritance?

Output:
B->Hello! from Explicit.

Shouldn't it be:?
A->Hello! from Explicit.

Why doesn't explicit cast (IHello)a call IHello.Hello() from class A?

interface IHello
{
    void Hello();
}

class A : IHello
{

    public virtual void Hello()
    {
        Console.WriteLine("A->Hello!");
    }

    void IHello.Hello()
    {
        Console.WriteLine("A->Hello! from Explicit.");
    }
}

class B : A, IHello
{
    public override void Hello()
    {
        Console.WriteLine("B->Hello!");
    }

    void IHello.Hello()
    {
        Console.WriteLine("B->Hello! from Explicit.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new B();
        ((IHello)a).Hello();
    }
}
like image 691
Naximus Avatar asked Dec 06 '09 20:12

Naximus


2 Answers

No, it shouldn't.

The call to Hello is equivalent to the commented-out one - the route to getting an IHello doesn't matter (unless it requires execution-time checking or conversion); the compile-time type is just IHello either way, and the interface mapping is the same however you get there.

When an interface is explicitly implemented more than once in the type hierarchy, the implementation in the most-derived type is used. (When called via the interface.)

From section 13.4.4 of the C# 3.0 Specification:

Interface mapping for a class or struct C locates an implementation for each member of each interface specified in the base class list of C. The implementation of a particular interface member I.M, where I is the interface in which the member M is declared, is determined by examining each class or struct S, starting with C and repeating for each successive base class of C, until a match is located:

  • If S contains a declaration of an explicit interface member implementation that matches I and M, then this member is the implementation of I.M.
  • Otherwise, if S contains a declaration of a non-static public member that matches M, then this member is the implementation of I.M. If more than one member matches, it is unspecified which member is the implementation of I.M. This situation can only occur if S is a constructed type where the two members as declared in the generic type have different signatures, but the type arguments make their signatures identical.
like image 69
Jon Skeet Avatar answered Sep 30 '22 01:09

Jon Skeet


(A)a does nothing. The reference is already declared as a so casting it to A will have no effect.

Even though your reference is declared as A, the object which it refers to is of type B. If you cast this object to IHello, a call to Hello() will call object B's explicit implementation of Hello.

The output is exactly as expected.

like image 30
Adam Ralph Avatar answered Sep 30 '22 00:09

Adam Ralph