问题
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