当前位置: 首页 > 知识库问答 >
问题:

C#调用接口方法非虚拟实现

尹俊贤
2023-03-14

我是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();

执行时<代码>----

当决定调用什么函数时--运行时还是编译时?如果我弄脏了一个新的< code>class CAble : IAble怎么办?

共有3个答案

钦景胜
2023-03-14

接口必须在直接继承自它的类中实现,而不是在派生类中实现。例如,此代码无法编译:

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");
    }
}

输出:<代码>-

或者我们可以使用多态性。这将告诉编译器总是使用被覆盖的函数:

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

class BAble : AAble, IAble
{
    public override void f()
    {
        Console.WriteLine("---->> B - Able");
    }
}
梅修贤
2023-03-14

通常会有编译器警告,因为它隐藏了一个方法。但在C#中,对非虚拟函数这样做是合法的。当然,如果它是一个虚拟函数,那么显然该方法的B版本将运行。

因为你将它声明为一个可变量,并且它是非虚拟的,编译器将它读为一个可变量。如果它被声明为虚拟的,编译器将扫描继承的层次结构,并会看到它的实际类是BAble,它将运行BAble代码。

闾丘德业
2023-03-14

因为< code>AAble正在实现< code>IAble接口,所以它的< code>AAble.f被标记为类型< code>AAble的< code>IAble.f方法的实现。

< code>BAble.f只是隐藏了< code>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中被标记为虚拟,即使它在C#中没有被标记为虚拟。该方法在IL中也被标记为最终,如果该方法在C#中是虚拟,它就不会被标记为最终

 类似资料:
  • 让我们在Visual C 2010中假设以下场景: 理论上,这个小应用程序的输出应该是: 基本:非虚拟显示。 基础:虚拟显示。 基本:非虚拟显示。 派生:虚拟显示。 因为基类的显示方法不是虚拟方法,所以派生类不能重写它。正当 问题是,当我运行应用程序时,它会打印以下内容: < li >基本:非虚拟显示。 < li >基本:虚拟显示。 < li >派生:非虚拟显示。 < li >派生:虚拟显示。 所

  • 问题内容: 我有一个定义方法的接口。我有一个 实现 此接口的结构。在其中,我已经从该接口实现了方法,并且还定义了其他方法。 例如: 在操场上:https : //play.golang.org/p/B1GgoNToNl_l 在此,WagTail()不是Animal接口的一部分,但属于Dog结构。运行此代码会出现错误 dog.WagTail未定义(动物类型没有字段或方法WagTail)。 有没有一种

  • 问题内容: 我正在尝试获取一些信息,但我的应用程序崩溃并显示以下消息: 这是代码: 这是一个纯课。的哪个调用不包含this 。我做错了吗?应始终位于内吗? 根据要求整体: 问题答案: 改成 您为布局充气。视图属于膨胀的布局。因此,使用view对象在中初始化视图 片段由活动主持 您可以在视图中使用和初始化 还在中初始化TextView 。由于Asynctask是一个内部类,因此您可以在那里更新ui

  • 问题内容: Java-8允许在接口内部定义静态方法,但仅通过接口名称限制其调用: 9.4:接口可以声明静态方法,这些方法在不引用特定对象的情况下被调用。 例如: 导致错误: 在JLS中,这种禁令经常有一种解释。在这种情况下,我没有发现任何详细信息。因此,我正在寻找对此规则的全面或权威的解释:为什么禁止通过特定的对象引用调用静态方法?它有什么坏处? 问题答案: 相当强烈的共识是,有关类的静态方法也不

  • 所以,基本上我创建了一个包装器类,它创建了一个简单的OpenGL应用程序。我的想法是在准备好的时候有这样的东西: 所以,基本上这个类使用GLFW封装了一个简单的OpenGL窗口。这个想法是,当你想要创建一个新的应用程序时,你只需要从应用程序类(我正在写的)派生你的类。使用这个新类,您只需重写虚拟方法(main Loop、初始化和回调),您将拥有一个工作应用程序。 下面是基类: 所以我所做的是将在派

  • 当我运行我的应用程序时,我有一个异常显示,所以我想帮助我:)异常是:java。lang.NullPointerException:尝试调用虚拟方法“int java”。lang.String。空对象引用上的长度() 当我单击Login类中的dd1按钮和按钮实现(public void getData(View v))方法时,会显示异常 非常感谢。 登录类 HttpManager类 日志: