假设我正在制作游戏并拥有基础Buff
课程。我可能还有一个名为ThornsBuff
的子类,它订阅Player
类的Damaged
事件。
Player
可能包含Buff
个列表,其中一个可能是ThornsBuff
。例如:
Player player = new Player();
player.ActiveBuffs.Add(new ThornsBuff(player));
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个引用,该事件仍在运行。我想这是因为垃圾收集器还没有运行?有没有办法让它自动和即时,以便当对象没有引用时,它的所有事件都是未注册的?
感谢。
答案 0 :(得分: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方法的情况下删除事件处理程序,为此以下是一些建议:
在player_DamageTaken开始时,检查是否有player.ActiveBuffs.Contains(this),如果没有,则调用player.DamageTaken - = player_DamageTaken并返回。这样做的缺点是,每次受到伤害时,你都会搜索整个Buff名单。
使ActiveBuffs成为一个ObservableCollection(或类似的东西),可以在从列表中删除buff时监听。如果是,您可以自动调用buff.Dispel,以便开发人员不必记住调用它。
答案 1 :(得分:0)
我不明白为什么当从列表中删除Buff时事件不会自动解除。
因为将Buff附加到列表并不是附加事件的内容。附加事件是因为您将其附加到构造函数中。玩家类实例现在也在其DamangeTake事件中引用了该buff,因此将其从Buffs列表中删除是不足以允许对象被垃圾收集...因此buff继续存在。
人们想知道为什么你在这里使用事件。为什么不在播放器中使用代码来迭代列表中的每个buff,并运行一些定义为接口一部分的方法,将损坏作为参数或返回值。那会更多你正在寻找的东西。
或者,在您目前删除buff的任何地方,您还需要代码来取消订阅它的事件。