强制父类方法调用重写的方法,而不是子重写

时间:2018-11-30 04:41:51

标签: c# inheritance override

public class C1 {
    public virtual void A() { Console.WriteLine("Good"); }
    public void B() { A(); } // <-- wrong A when when called in child classes :(
}
public class C2 : C1 {
    public override void A() { B(); }
}

在C2中我能做些什么,以便当C2.A()调用B()时,下一个调用是C1.A()而不是C2.A(),从而导致无限递归?

4 个答案:

答案 0 :(得分:0)

这还不够吗?将A的实现移到基类的一个单独的私有方法中,然后从基类中调用它吗?

public class C1 {
    private void AImplementation() { Console.WriteLine("Good"); }
    public virtual void A() { AImplementation(); }
    public void B() { AImplementation(); }
}
public class C2 : C1 {
    public override void A() { B(); }
}

答案 1 :(得分:0)

了解您完全处于hack模式下会有所帮助。与其他建议相比,该技巧可能在更多情况下有效。但这慢了。此实现尝试尽可能通用。但是,如果您只想解决此特定示例,则可能只需抓住适当的硬编码索引并检查/比较声明类型的帧即可。

public class C1 {
    public virtual void A() { Console.WriteLine("Good"); }
    public void B() { A(); }
}
public class C2 : C1 {
    public override void A()
    {
        var method = new System.Diagnostics.StackTrace()
                    .GetFrames().Skip(1).Select(f => f.GetMethod())
                    .FirstOrDefault(m => m.Name == nameof(A) && m.DeclaringType == typeof(C2));
        if (method == null) B();
        else base.A();
    }
}

或者,就像我说的那样,您可以检查

var method = new System.Diagnostics.StackTrace().GetFrame(2).GetMethod();
if (method.Name != nameof(A)) B();
else base.A();

尽管其他人都说过,这是一个糟糕的解决方案,如果可以的话,您可以通过更好的设计来解决。

答案 2 :(得分:-1)

IRC上的一位乐于助人的人提供了这个骇人的非线程安全解决方案:

public class C1 {
    public virtual void A() { Console.WriteLine("Good"); }
    public void B() { A(); }
}
public class C2 : C1 {
    bool _aOnCallStack = false;
    public override void A() { 
        if (!_aOnCallStack) {
            _aOnCallStack = true;
            B(); 
        }
        else {
            base.A();
            _aOnCallStack = false;
        }
    }
}

答案 3 :(得分:-1)

我不得不重命名您的类和方法-As,B和C使我发疯。

注意:,这是重做操作,在您评论了基类必须单独放置之后。我认为这回答了您的问题。 hacky,但我认为应该可以使用:

public class Base {
    public virtual void TheVirtualFunction() {
        Console.WriteLine($"Base Class Implemenation of Virtual Function from type {GetType().Name}");
    }
    public void NonVirtualFuction() {
        Console.WriteLine($"The non-Virtual Function - Calling Vitual function now from type {GetType().Name}");
        TheVirtualFunction();
    }
}

public class Sub : Base
{
    private bool _isCallingAgain = false;
    public override void TheVirtualFunction()
    {
        Console.WriteLine($"Sub Class Implemenation of Virtual Function from type {GetType().Name}");
        if (_isCallingAgain)
        {
            Console.WriteLine($"Skipping because v-func called twice from type {GetType().Name}");
            return;
        }
        _isCallingAgain = true;
        Console.WriteLine($"This pass through the virtual function does something (from type {GetType().Name})");
        NonVirtualFuction();
        _isCallingAgain = false;
    }
}

然后,在我的Main函数中,我的代码如下:

static void Main(string[] args) {
    var theBase = new Base();
    Console.WriteLine("Calling Base Class Non Virtual function");
    theBase.NonVirtualFuction();

    Console.WriteLine("\r\nCalling Base Class Virtual function directly");
    theBase.TheVirtualFunction();

    var theSub = new Sub();
    Console.WriteLine("\r\nCalling Non-Virtual Function (implemented in the base class) using sub-class reference");
    theSub.NonVirtualFuction();

    Console.WriteLine("\r\nCalling Sub Class Virtual function directly");
    theSub.TheVirtualFunction();

    Console.ReadLine();
}

这一切的结果都会喷到控制台上

Calling Base Class Non Virtual function
The non-Virtual Function - Calling Vitual function now from type Base
Base Class Implemenation of Virtual Function from type Base

Calling Base Class Virtual function directly
Base Class Implemenation of Virtual Function from type Base

Calling Non-Virtual Function (implemented in the base class) using sub-class reference
The non-Virtual Function - Calling Vitual function now from type Sub
Sub Class Implemenation of Virtual Function from type Sub
This pass through the virtual function does something (from type Sub)
The non-Virtual Function - Calling Vitual function now from type Sub
Sub Class Implemenation of Virtual Function from type Sub
Skipping because v-func called twice from type Sub

Calling Sub Class Virtual function directly
Sub Class Implemenation of Virtual Function from type Sub
This pass through the virtual function does something (from type Sub)
The non-Virtual Function - Calling Vitual function now from type Sub
Sub Class Implemenation of Virtual Function from type Sub
Skipping because v-func called twice from type Sub

请注意,它两次调用了子类虚函数,但是保护位使它从第二次开始就不再做任何事情。这几乎就是您想出的,但是我是独立完成的。

保护位(_isCallingAgain)是私有实例成员变量。它必须在单个执行线程上进行访问(执行路径进入Sub的v-func,进入Base的非虚拟函数,然后再次返回Sub的v-func)。

无需用lock或其他来保护它(除了确保它是private之外)。

我认为这是您的唯一选择。像这样的非重入式防护是一种很常见的模式(在我进行MFC和Win32 Windows UI编程的那一天,这很常见)。