对于简单脚本,始终在 Override 中调用 base.Method 而无需提及它

Yos*_*rgi 3 c# game-engine

我正在尝试将 C# 实现为我的游戏引擎的脚本语言。一切工作正常,我的设计中只出现了一个主要问题。

我有 BaseEntity 类。另一个类 BossEntity 派生自 BaseEntity。然后我希望能够通过脚本创建一个新实体。因此,我在脚本中创建一个类(假设为 Boss1),它派生自 BossEntity。

BaseEntity 有一个虚拟的 Update 方法。BossEntity 覆盖它并调用 base.Update()。设计上一切都很好。

但现在我的问题来了。在我的脚本中,我还希望能够覆盖更新方法。所以我继续并再次覆盖它。一切都按预期进行,BossEntity 覆盖丢失,因为我现在再次覆盖 BaseEntity 更新。

但为了简单起见,我不想调用我的脚本 base.Update() 来获得与 BossEntity 中相同的行为。这是一件可以被忘记的事情,对于我来说,就像脚本语言的糟糕设计一样。

在我看来,编写脚本时您只是添加功能而不是删除某些功能。

所以我的一般问题是,有没有什么方法可以完成对 base.Update() 的调用,甚至无需在我的脚本中额外调用它?

我认为不会,或者可能只是用了一个技巧,但你永远不知道。

Joh*_*ger 5

据我所知,当调用重写的方法时,没有办法自动调用基类的虚拟方法。您必须显式调用它。

您可以做的事情之一就是进一步分解父方法。而不是将所有代码放在一个可重写的方法中,如下所示:

public class Foo
{
    public virtual void Update()
    {
        // Do stuff
    }
}

public class Bar : Foo
{
    public override void Update()
    {
        // Replaces the parents implementation of the 
        // Update method due to not calling base.Load();
    }
}
Run Code Online (Sandbox Code Playgroud)

相反,您可以使用模板方法模式将其分成多个部分,以便用户可以覆盖明确适合他们的部分。

public class Foo
{
    public void Update()
    {
        this.OnUpdating();
        this.PerformUpdate();
        this.OnUpdated();
    }

    public virtual void PerformUpdate()
    {
        // Leave this empty. Let the subclass override it and
        // do their own thing. Your parent code will still
        // get called when Update() is called.
    }

    public void OnUpdating()
    {
        // Invoke code that you want to guarantee is always
        // executed PRIOR the overridden PerformUpdate() method
        // is finished.
    }

    public void OnUpdated()
    {
        // Invoke code that you want to guarantee is always
        // executed AFTER the overridden PerformUpdate() method
        // is finished.
    }
}

public class Bar : Foo
{
    public override void PerformUpdate()
    {
        // Do custom stuff, don't have to call base.PerformUpdate()
        // because it already does it's code in OnUpdating() 
        // and OnUpdated().
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这是有道理的。这就是我在游戏引擎中所做的。然后我记录不需要调用 base.PerformUpdate() 。另一种选择是使PerformUpdate()方法抽象,迫使子级实现它。这使得不需要调用 更加清楚base.PerformUpdate()

public class Foo
{
    public void Update()
    {
        this.OnUpdating();
        this.PerformUpdate();
        this.OnUpdated();
    }

    // Child class is required to implement this method. 
    // Only downside is you will no longer be able to instance 
    // the base class. If that is acceptable, then this is really 
    // the preferred way IMO for what you are wanting to do.
    public abstract void PerformUpdate();

    public void OnUpdating()
    {
        // Invoke code that you want to guarantee is always 
        // executed PRIOR the overridden PerformUpdate() method is finished.
    }

    public void OnUpdated()
    {
        // Invoke code that you want to guarantee is always 
        // executed AFTER the overridden PerformUpdate() method is finished.
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,这种方法通过强制子类实现您不依赖的自己的更新方法,让您的基类安全地处理其更新代码。您的基类可以在子类运行更新之前和之后运行其更新内容。

这基本上可以让您在游戏代码中执行此操作:

Bar myFoo = new Bar();
myFoo.Update();
Run Code Online (Sandbox Code Playgroud)

您可以放心,您的基类更新方法将被调用,子更新代码也将被调用。