C# - force overridden method to be called by parent, not by instance

时间:2015-11-12 10:37:49

标签: c# override abstract

I'm trying to find a proper way to restrict/force the usage of methods in order to ensure the correct internal handling.

Given the following abstract base class

public abstract class BaseClass
{
    // needs to be overriden by concrete implementation
    protected abstract void CreateInternal(object dataToCreate);

    // only visible method
    public void Create(object dataToCreate)
    {
        // check the data provided <-- this is important to be done each time
        CheckData(dataToCreate);

        // call implementation of concrete class
        CreateInternal(dataToCreate);
    }

    private void CheckData(object dataToCheck)
    {
        if(dataToCheck == null) throw new Exception("Data is  not valid");
    }
}

and a simple implementation

public class ChildClass : BaseClass
{
    protected override void CreateInternal(object dataToCreate)
    {
        // do create-stuff related to ChildClass
    }
}

My question: Is there a way to restrict the access to CreateInternal? In ChildClass I could create a public method

public void DoStuff(object dataToDoStuff)
{
    // access protected method is not forbidden
    CreateInternal(dataToDoStuff);
}

This will call CreateInternal without doing the needed checks as if it would do if called via Create of the base-class. Is there any way to force the usage of Create prior to CreateInternal? There is no need to have this at compile-time (but it would be nice), but at least at runtime.

I have something like checking who is calling in mind.

public class ChildClass : BaseClass
{
    protected override void CreateInternal(object dataToCreate)
    {
        // if not called via base 'Create' -> throw exception
    }
}

Is there some pattern I'm not aware of or is what I'm trying to achieve too weired and simply not possible?

2 个答案:

答案 0 :(得分:2)

There is no way of really enforcing this at compile or runtime. As you well say, a virtual protected method is reachable and overridable from any derived type so you'd always have to rely on the implementation of the overriden method making the necessary checks which kind of defeats the purpose.

IMHO your best bet is to enforce this through code reviews if you can control who's extending your class. If thats not the case then, seeing that your Create method is not virtual and is simply changing the state of BaseClass, why don't you call it in the constructor? Is this possible or is your example a simplified scenario and this isn't an option? Doing this would guarantee that Create is always called first.

UPDATE: Contrary to what I said before, there are "ways" you could enforce this at runtime.

Although not shown in your example, I'm guessing there will be some kind of internal state in BaseClass that any derived class must leverage via methods, properties, fields, etc. to be of any use (inheritance would be kind of pointless otherwise). You could always set a private flag createCalled in BaseClass and make all BaseClass methods, getters (yuck) and setters check the flag and bail out with an InvalidOperationException if its not set. This would esentially render useless any derived instance not correctly initialized. Ugly but doable.

Or even simpler, if you control all potential consumers of BaseClass and any derived type out there in the wild, then just make the flag public public bool Initialized { get; }and check when consuming the object and bail out if necessary.

答案 1 :(得分:0)

"Weird" would not be the word of choice of mine, but still..

As far as I can see, what you are trying to achieve is to prevent the ChildClass owner, who implemented CreateInternal()'s method body, from executing those statements without invoking CheckData() first.

Even if this works, he can still copy and paste the statements into DoStuff() method body and can execute them there.

We do not force, we guide.

People will follow your guideline, and they will be happy to see that their class is working according to it.