C#-强制重写的方法由父级调用,而不是由实例调用

本文关键字:调用 实例 重写 方法 C#- | 更新日期: 2023-09-27 18:21:35

我正试图找到一种适当的方法来限制/强制使用方法,以确保正确的内部处理。

给定以下抽象基类

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

和一个简单的实现

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

我的问题是:有没有办法限制对CreateInternal的访问?在ChildClass中,我可以创建一个公共方法

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

这将调用CreateInternal,而不进行所需的检查,就像通过基类的Create调用一样。有没有办法强制在CreateInternal之前使用Create?编译时不需要这样做(但这会很好),但至少在运行时是这样。

我有点想看看谁在打电话。

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

是不是有一些我不知道的模式,或者我试图实现的目标太过模糊,根本不可能实现?

C#-强制重写的方法由父级调用,而不是由实例调用

在编译或运行时没有办法真正强制执行这一点。正如您所说,virtual protected方法是可访问的,并且可以从任何派生类型重写,因此您必须始终依赖于overriden方法的实现来进行必要的检查,这种检查会破坏目的。

IMHO如果你能控制谁在扩展你的类,你最好的办法就是通过代码审查来强制执行这一点。如果不是这样的话,那么,既然你的Create方法不是虚拟的,只是在改变BaseClass的状态,为什么不在构造函数中调用它呢?这可能吗?或者你的例子是一个简化的场景,而这不是一个选项?这样做将保证Create总是首先被调用。

UPDATE:与我之前所说的相反,有一些"方法"可以在运行时强制执行。

虽然您的示例中没有显示,但我猜BaseClass中会有某种内部状态,任何派生类都必须通过方法、属性、字段等来利用这种状态才能使用(否则继承就没有意义了)。您可以始终在BaseClass中设置一个私有标志createCalled,并让所有BaseClass方法、getter(yuck)和setter检查该标志,如果未设置,则使用InvalidOperationException退出。这将使任何未正确初始化的派生实例变得毫无用处。丑陋但可行。

或者更简单的是,如果您控制BaseClass的所有潜在消费者以及任何在野外的派生类型,那么只需将标志设为公共public bool Initialized { get; },并在消费对象时进行检查,并在必要时退出。

"怪异"不会是我的首选词,但仍然。。

据我所见,您试图实现的是防止实现CreateInternal()的方法体的ChildClass所有者在不首先调用CheckData()的情况下执行这些语句。

即使这样做有效,他仍然可以将语句复制并粘贴到DoStuff()方法体中,并可以在那里执行它们。

我们不强迫,我们引导。

人们会遵循你的指导方针,他们会很高兴看到他们的班级按照它工作。