0

假设我正在制作游戏并且有一个基Buff类。我也可能有一个名为的子类ThornsBuff订阅Player该类的Damaged事件。

Player可能有一个 s 列表,其中Buff一个可能是ThornsBuff。例如:

测试班

Player player = new Player();
player.ActiveBuffs.Add(new ThornsBuff(player));

ThornsBuff 类

public ThornsBuff(Player player)
{
    player.DamageTaken += player_DamageTaken;
}

private void player_DamageTaken(MessagePlayerDamaged m)
{
    m.Assailant.Stats.Health -= (int)(m.DamageAmount * .25);
}

这都是为了说明一个例子。如果我要从列表中删除 buff,则事件不会分离。即使玩家不再拥有 buff,事件仍会像他一样执行。

现在,我可以有一个Dispel方法来取消注册该事件,但这会迫使开发人员调用Dispel除了Buff从列表中删除之外。如果他们忘记了,增加耦合等怎么办?

Buff我不明白为什么从列表中删除事件时事件不会自动分离。Buff唯一存在于列表中,这是它的一个参考。删除后不应该分离事件吗?

我尝试将分离代码添加到终结器中,Buff但这也没有解决它。即使事件有 0 个引用,该事件仍在运行。我想这是因为垃圾收集器还没有运行?有没有办法让它自动和即时,这样当对象没有引用时,它的所有事件都是未注册的?

谢谢。

4

2 回答 2

1

无论 Buff 是否在 ActiveBuffs 列表中,都会继续调用事件 (player_DamageTaken)。这是因为当您运行 DamageTaken += player_DamageTaken 时,它会创建一个从 player.DamageTaken 到该 ThornsBuff 实例及其 player_DamageTaken 方法的引用。(否则,运行时如何知道在哪个 ThornsBuff 实例上调用 player_DamageTaken?)

该引用将继续存在,直到您调用 player.DamageTaken - = player_DamageTaken。您还将Buff 添加到 ActiveBuffs的事实只是添加了对 buff 的另一个引用,这在技术上不是必需的(但在我看来,这是一种很好的形式,因为我不喜欢挂起未引用的事件处理程序)。

现在您可能想知道如何在不导致开发人员调用额外的 Dispel 或 Dispose 方法的情况下删除事件处理程序,对此有一些建议:

  1. 在 player_DamageTaken 的开头检查是否 player.ActiveBuffs.Contains(this),如果没有,则调用 player.DamageTaken -= player_DamageTaken 并返回。这样做的缺点是每次受到伤害时你都在搜索整个增益列表。

  2. 使 ActiveBuffs 成为 ObservableCollection(或类似的东西),可以在从列表中删除 buff 时进行监听。当它们存在时,您可以自动调用 buff.Dispel,这样开发人员就不必记得调用它了。

于 2012-11-18T04:47:30.513 回答
0

我不明白的是为什么当 Buff 从列表中删除时事件不会自动分离。

因为将 Buff 附加到列表中并不是附加事件的原因。该事件已附加,因为您在构造函数中附加了它。玩家类实例现在在其 DamangeTake 事件中也有对该 buff 的引用,因此从 Buffs 列表中删除它不足以让对象被垃圾收集......因此 buff 继续存在。

有人想知道你为什么在这里使用事件。为什么不在播放器中使用代码来遍历列表中的每个 buff 并运行定义为接口一部分的某些方法,并将损坏作为参数或返回值。这会做更多你正在寻找的东西。

或者,在您当前删除 buff 的任何地方,您还需要代码来取消订阅它的事件。

于 2012-11-18T04:57:35.150 回答