我正在尝试将 C# 实现为我的游戏引擎的脚本语言。一切工作正常,我的设计中只出现了一个主要问题。
我有 BaseEntity 类。另一个类 BossEntity 派生自 BaseEntity。然后我希望能够通过脚本创建一个新实体。因此,我在脚本中创建一个类(假设为 Boss1),它派生自 BossEntity。
BaseEntity 有一个虚拟的 Update 方法。BossEntity 覆盖它并调用 base.Update()。设计上一切都很好。
但现在我的问题来了。在我的脚本中,我还希望能够覆盖更新方法。所以我继续并再次覆盖它。一切都按预期进行,BossEntity 覆盖丢失,因为我现在再次覆盖 BaseEntity 更新。
但为了简单起见,我不想调用我的脚本 base.Update() 来获得与 BossEntity 中相同的行为。这是一件可以被忘记的事情,对于我来说,就像脚本语言的糟糕设计一样。
在我看来,编写脚本时您只是添加功能而不是删除某些功能。
所以我的一般问题是,有没有什么方法可以完成对 base.Update() 的调用,甚至无需在我的脚本中额外调用它?
我认为不会,或者可能只是用了一个技巧,但你永远不知道。
据我所知,当调用重写的方法时,没有办法自动调用基类的虚拟方法。您必须显式调用它。
您可以做的事情之一就是进一步分解父方法。而不是将所有代码放在一个可重写的方法中,如下所示:
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)
您可以放心,您的基类更新方法将被调用,子更新代码也将被调用。