[英]C# call an interface method non-virtual implementation
我是C#的新手,我不明白为什么编译器不会抱怨这段代码。 这是类的层次结构:
interface IAble
{
void f();
}
class AAble : IAble
{
public void f()
{
Debug.Log("---->> A - Able");
}
}
class BAble : AAble
{
public void f()
{
Debug.Log("---->> B - Able");
}
}
执行代码:
IAble i = new BAble();
i.f();
执行---->> A - Able
被打印出来。 为什么? 编译器如何知道应该调用哪个函数?
当决定调用什么函数 - 运行时或编译时? 如果我玷污一个新的class CAble : IAble
怎么class CAble : IAble
?
因为AAble
正在实现IAble
接口,所以它的AAble.f
被标记为类型AAble
的IAble.f
方法的实现。
BAble.f
只是隐藏了AAble.f
方法,它没有覆盖它。
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
决定是在编译时做出的:
// 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
接口实现在IL中标记为virtual
,即使它未在C#中标记为虚拟。 该方法在IL中也标记为final
,如果该方法在C#中是virtual
,则它不会被标记为final
。
通常会有一个编译器警告,因为它隐藏了一个方法。 但在C#中,非虚拟功能是合法的。 当然,如果它是虚函数,那么显然该方法的B版本将运行。
因为您将其声明为IAble并且它是非虚拟的,所以编译器将其作为IAble读取。 如果它被声明为虚拟,则编译器将扫描继承的层次结构,并且会看到它的实际类是BAble并且它将运行BAble代码。
在派生类中定义具有与基类相同签名的方法时,您将隐藏它。
这意味着当您使用基类型声明变量并使用dervied类型初始化它时,将使用基类中的方法。 这就是你的代码中的hapenning。
更一般:当你隐藏方法时,那么将使用的方法的版本,来自你声明它的类的cmoes。
所以,如果你有另一个类CAble
并使用如下:
BAble c = new CAble();
b.f();
然后结果将是---->> B - Able
。
在您的情况下,您将IAble
声明为IAble
。 它没有实现,因此它着眼于实现,它在类AAble
定义。 其他类只隐藏方法。
为了隐藏方法,您可以使用相同的签名指定两个方法。 但是你应该总是使用new
keywrods来明确隐藏方法(这表明隐藏是故意的)。
您期望的是重写方法,在定义方法时使用override
keywaord完成。
为了覆盖方法,它应该在基类中标记为virtual
(如果它具有实现)或abstract
(如果它没有实现)。
接口必须在直接从它继承的类中实现,而不是在派生类之一中实现。 例如,此代码将无法编译:
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");
}
}
当我们上溯造型BAble
接口IAble
从实现AAble
被使用,因为它是从实现该接口编译准的唯一类。
我们可以直接从接口继承,这将告诉编译器应该使用哪个接口的实现:
class BAble : AAble, IAble
{
// Now it compiles
void IAble.f()
{
Console.WriteLine("---->> B - Able");
}
}
输出: ---->> B - Able"
或者我们可以使用多态。 这将告诉编译器始终使用重写的函数:
class AAble : IAble
{
public virtual void f()
{
Debug.Log("---->> A - Able");
}
}
class BAble : AAble, IAble
{
public override void f()
{
Console.WriteLine("---->> B - Able");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.