Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
351 views
in Technique[技术] by (71.8m points)

interface - Why does this C# code return what it does

Can someone please help me understand why this code snippet returns "Bar-Bar-Quux"? I'm having a hard time understanding this even after reading up on interfaces.

interface IFoo
{ 
    string GetName();
}

class Bar : IFoo
{
    public string GetName() { return "Bar"; }
}

class Baz : Bar
{
    public new string GetName() { return "Baz"; }
}

class Quux : Bar, IFoo
{
    public new string GetName() { return "Quux"; }
}

class Program
{
    static void Main()
    {
        Bar f1 = new Baz();
        IFoo f2 = new Baz();
        IFoo f3 = new Quux();
        Console.WriteLine(f1.GetName() + "-" + f2.GetName() + "-" + f3.GetName());
    }
}
question from:https://stackoverflow.com/questions/25008021/why-does-this-c-sharp-code-return-what-it-does

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are two things happening here. One is member hiding. This is fairly well-known and covered elsewhere. The other, less-known feature is interface re-implementation covered in section 13.4.6 of the C# 5 specification. To quote:

A class that inherits an interface implementation is permitted to re-implement the interface by including it in the base class list. A re-implementation of an interface follows exactly the same interface mapping rules as an initial implementation of an interface. Thus, the inherited interface mapping has no effect whatsoever on the interface mapping established for the re-implementation of the interface.

and

Inherited public member declarations and inherited explicit interface member declarations participate in the interface mapping process for re-implemented interfaces.

The result for f1.GetName() is "Bar" because the method Baz.GetName is hiding Bar.GetName and f1 is declared as type Bar. There is no dispatch to the run-time type's implementation unless it is explicitly declared as virtual and overridden.

Similarly, for f2.GetName(), Baz.GetName is hiding the implementation in Bar, so it is not called when using dispatch through a reference to the interface. The interface is "mapped" to the method declared in Bar because that is the type on which the interface was declared. It does not matter that Baz has a compatible method with the same name. The rules for interface mapping are defined in section 13.4.4 of the spec. If GetName had been declared virtual in Bar, it could be overridden, which then would be called through the interface. The result is therefore also "Bar".

For f3.GetName(), Quux re-implements IFoo so it gets to define its own mapping to GetName. Note that it also hides the implementation inherited from Bar. It is not necessary to use new to do the re-implementation, it simply suppresses the warning about hiding. Therefore the result is "Quux".

So that explains the output that you see: "Bar-Bar-Quux"

This post by Eric Lippert discuss some more nuances in this tricky feature.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...