【问题标题】:base.Method() with multiple levels of inheritance not being called?没有调用具有多级继承的 base.Method()?
【发布时间】:2013-04-28 22:13:55
【问题描述】:

我已经搜索过,但找不到任何解决我的问题的方法。我的场景很简单:

public class A
{
    public virtual void MethodOne()
    {
       Console.log( "A" ); 
    }
}

public class B : A
{
    public override void MethodOne()
    {
        base.MethodOne();
        Console.log( "B" );
    }
}

public class C : B
{
    public override void MethodOne()
    {
        base.MethodOne();
        Console.log( "C" );
    }
}

我想要做的是让 C 类的一个实例(我们将其命名为“instanceC”)同时调用其父级和祖父级的重写方法。所以我希望这样:

instanceC.MethodOne();
// Output:
// "A"
// "B"
// "C"

但是却得到了这个:

instanceC.MethodOne();
// Output
// "A"
// "C"

B 类的方法被跳过。这不可能吗?我认为这是继承/多态性的重点。提前致谢!

【问题讨论】:

  • 你确定C是从B而不是A派生的吗?
  • 为什么 C 会从 B 覆盖?您希望它从 A 继承。
  • 您的示例对我来说按预期工作并打印“A B C”
  • 对我来说也一样,您的示例有效,您的原始代码一定有什么遗漏或错误
  • @Derek 如果您需要执行 B 的某些行为,但需要在调用之前或之后添加其他行为。由于 XmlReader.Parse 在无效的 ASCII 字符上爆炸,我曾经不得不覆盖 FileStream。我能够覆盖 GetBytes,调用 base.GetBytes 从 FileStream 获取结果,将无效值更改为替换字符,然后将其传递给 XmlReader.Create

标签: c# .net inheritance base-class


【解决方案1】:

您的示例对我来说按预期工作。我看到 A B C。我认为您最可能的问题是 C 没有扩展 B。但是,在我们讨论这个主题时,让我提出一个可以说更安全的模式。您似乎希望 MethodOne 的所有覆盖都从其基类执行代码。太好了,继承是一个很好的模式。但是,使用这种模式,您无法强制继承者执行基本逻辑,因为您无法强制它们调用base.MethodOne()。即使他们确实调用base.MethodOne(),您也无法确保逻辑的顺序。他们会在方法的开头、方法的中间还是方法的结尾调用base.MethodOne()?通常,在这些类型的模式中,您希望子类在函数的开头执行所有基本逻辑。以下模式强制继承者按照基类期望的顺序执行基本逻辑。它在技术上不太灵活但更安全,因为继承者必须以基类指定的方式扩展基类。

public class A
{
    //Don't make this method virtual because you don't actually want inheritors 
    //to be able to override this functionality.  Instead, you want inheritors
    //to be able to append to this functionality.
    public void MethodOne()
    {
        Console.WriteLine( "A" ); 
        MethodToBeOverriddenOne();
    }
    //Expose a place where inheritors can add extra functionality
    protected virtual void MethodToBeOverriddenOne() { }      
}

public class B : A
{
    //Seal the method because you don't actually want inheritors 
    //to be able to override this functionality.  Instead, you want inheritors
    //to be able to append to this functionality.
    protected sealed override void MethodToBeOverriddenOne()
    {
        Console.WriteLine("B");
        MethodToBeOverriddenTwo();
    }
    //Expose a place where inheritors can add extra functionality
    protected virtual void MethodToBeOverriddenTwo() { }  
}

public class C : B
{
    protected sealed override void MethodToBeOverriddenTwo()
    {
        Console.WriteLine("C");
    }
}

【讨论】:

  • 这是一个比另一个更好的答案,因为它清楚地展示了如何确保始终调用基本方法。不知道为什么它被否决了。
  • 我睡得很少,你们是对的; C 愚蠢地扩展了 A 而不是 C。所以虽然这确实是问题所在,但我确实认为这是一个更好的解决方案,并且效果很好。谢谢!
  • 不是我投反对票吗,我认为它也比我的好并给了它一个 +1
  • 我知道很老的问题,但我只是想补充一点,如果这就是你想要的,这显然是一个很好的模式。如果您需要客户端能够禁用基类功能(并实际覆盖它),这不是要走的路。当然,那你首先会打电话给base.MethodOne()
【解决方案2】:

您发布的示例完美运行,无论您在实际代码中做什么都与您发布的不同。

Here is your code running on ideone 完全按照您的意愿工作。

using System;

public class Test
{
        public static void Main()
        {
                var c = new C();
                c.MethodOne();
        }
}

public class A
{
    public virtual void MethodOne()
    {
       Console.WriteLine( "A" ); 
    }
}

public class B : A
{
    public override void MethodOne()
    {
        base.MethodOne();
        Console.WriteLine( "B" );
    }
}

public class C : B
{
    public override void MethodOne()
    {
        base.MethodOne();
        Console.WriteLine( "C" );
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    • 2014-10-12
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多