C# call an interface method non-virtual implementation

牧云@^-^@ 提交于 2019-12-12 11:19:51

问题


I am new to C# and I don't understand why compiler does not complain on this code. Here is the hierarchy of classes:

interface IAble
{
    void f();
}

class AAble : IAble
{
    public void f()
    {
        Debug.Log("---->> A - Able");
    }
}

class BAble : AAble
{
    public void f()
    {
        Debug.Log("---->> B - Able");
    }
}

execution code:

        IAble i = new BAble();
        i.f();

On execution ---->> A - Able was printed. Why? How the compiler knows what function should be called?

When the decision is made of what function to call - runtime or compile time? What if I defile a new class class CAble : IAble?


回答1:


Because AAble is implementing the IAble interface, its AAble.f is marked as the implementation of the IAble.f method for type AAble.

BAble.f is simply hiding the AAble.f method, it is not overriding it.

IAble o = new BAble(); o.f(); // calls AAble.f
AAble o = new BAble(); o.f(); // calls AAble.f
BAble o = new BAble(); o.f(); // calls BAble.f
IAble o = new CAble(); o.f(); // calls CAble.f

The decision is made at compile-time:

// AAble.f in IL:
.method public final hidebysig newslot virtual 
    instance void f () cil managed 

// BAble.f in IL:
.method public hidebysig 
    instance void f () cil managed

Interface implementations are marked as virtual in IL, even though it wasn't marked virtual in C#. The method is also marked as final in IL, if the method would've been virtual in C#, it would not have been marked as final.




回答2:


Normally there would be a compiler warning about this as it's hiding a method. but within C# it's legal to do for non-virtual functions. However of course, if it were a virtual function then obviously the B version of the method would run.

Because you declare it as an IAble and it's non-virtual, the compiler reads it as an IAble. If it were declared virtual, the compiler would scan through the hierarchy of inheritance and would see that it's actual class is a BAble and it would run the BAble code.




回答3:


Interface must be implemented in a class that inherits from it directly and not in one of derived classes. For instance this code won't compile:

class AAble : IAble
{
    public void f() { ... }
}

class BAble : AAble
{
    // An attempt to explicitly implement interface in BAble through AAble class
    void IAble.f()
    {
        Console.WriteLine("---->> B - Able");
    }
}

When we upcast BAble to interface IAble an implementation from AAble is used as it is the only class from compile prospective that implement the interface.

We could inherit from interface directly and this will tell compiler that which implementation of interface should be used:

class BAble : AAble, IAble
{
    // Now it compiles
    void IAble.f()
    {
        Console.WriteLine("---->> B - Able");
    }
}

Output: ---->> B - Able"

Or we could use polymorphism. This will tell compiler to always use the overridden function:

class AAble : IAble
{
    public virtual void f()
    {
        Debug.Log("---->> A - Able");
    }
}

class BAble : AAble, IAble
{
    public override void f()
    {
        Console.WriteLine("---->> B - Able");
    }
}



回答4:


When you define method in derived class that has the same signature as in the base class, you are hiding it.

It means when you declare variable with base type and initialize it with dervied type, then method from the base class will be used. That's what hapenning in your code.

More general: when you hide methods, then version of a method that will be used, cmoes from the class that you declared it with.

So if you had another class CAble and used like:

BAble c = new CAble();
b.f();

then the result would be ---->> B - Able.

In your case, you declare variabble as IAble. It doesn't have implementation, so it looks at implementation, which is defined in class AAble. Other classes only hide the method.

In order to hide method, you can specify both methods with the same signature. But you should always use new keywrods, to explicitly hide the method (which will indicate, that hiding was on purpose).

What you expect is overriding methods, accomplshed by using override keywaord, when defining a method.

In order to override method, it should be marked as virtual (if it has implementation) or abstract (if it doesn't have implementation) in a base class.



来源:https://stackoverflow.com/questions/52203479/c-sharp-call-an-interface-method-non-virtual-implementation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!