简体   繁体   中英

Object Inheritance, Sealed Method Overrides, and C#

I've got an abstract class defined by another assembly (not editable):

public abstract class A
{
    public void Run()
    {
        Go("Hello World");
    }

    protected virtual void Go(string message)
    {
        // Do Nothing
    }
}

Now I have a library that I want to inherit from this class which implements Go(). The trick here is that I don't want anyone inheriting from me to be able to override my implementation of Go(), but I also don't want to change the signature in any way. I actually want both implementations to be called. Here's what I've got so far:

public abstract class B_Intercept : A
{
    protected sealed override void Go(string message)
    {
        Console.WriteLine(message);
        Go_Impl(message);
    }

    internal abstract void Go_Impl(string message);
}

public abstract class B : B_Intercept
{
    protected new virtual void Go(string message)
    {
    }

    internal override void Go_Impl(string message)
    {
        Go(message);
    }
}

Now my end users can switch their class' inheritance from A to B with no effect (other than my Console.WriteLine).

public class C : A // This can be changed to B with no other edits
{
    protected override Go(string message)
    {
        // Do stuff
    }
}

Now, the original library can be given an instance of C, it'll be boxed as an A, and the original library will call Run(). Run will use B_Intercept's Go(), which will dump the message to console, then call Go_Impl(). Go_Impl will be run in B, which will call B's Go() which can be override by C.

This feels really circuitous.

There's an added benefit of some security around the methods (they can't call Go_Impl directly), but there are still holes (they can call base.Go). I think those holes can be closed up with a third layer, but I haven't tried it and frankly I think that's a bit ridiculous. But it still feels like a lot of boilerplate code. There's also the lame side effect of B_Intercept needing to be public instead of internal, which raises the surface area of my library in an unexplained way.

Is there a simpler, more secure way?

The issue here is that you are trying to do something which was not the intention of the developer of the original class.

Go has been provided as a virtual method and now you are trying to hide it while you want to keep it as OO as possible - ( UPDATE ) and not just that, you are also concerned about inherited classes calling base method. I earnestly congratulate you on your effort, care and attention but something has got to give .

Either you must use composition to wrap an A class and provide only the interfaces you intend to provide and fit your design or you have to use inheritance and accept its short-coming which mainly are arisen from the fact you are really changing the intended behaviour of the class. For my two cents, I would go with the first option: composition . At the end of the day, this is really what you are trying to achieve.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM