C# 当我的对象不再被引用时,为什么它的事件继续运行?

C# 当我的对象不再被引用时,为什么它的事件继续运行?,c#,events,event-handling,publish-subscribe,C#,Events,Event Handling,Publish Subscribe,假设我正在制作一个游戏,并且有一个基础Buff类。我可能还有一个名为ThornsBuff的子类,它订阅Player类的损坏事件 Player可能有一个Buffs列表,其中一个可能是ThornsBuff。例如: 测试班 ThornsBuff类 这只是一个例子。如果我要从列表中删除buff,则事件不会分离。即使玩家不再拥有增益,该事件仍然会像他那样执行 现在,我可以有一个dispure方法来注销事件,但是除了从列表中删除Buff之外,这迫使开发人员调用dispure。如果他们忘记了,耦合增加,等等怎

假设我正在制作一个游戏,并且有一个基础
Buff
类。我可能还有一个名为
ThornsBuff
的子类,它订阅
Player
类的
损坏事件

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

测试班 ThornsBuff类 这只是一个例子。如果我要从列表中删除buff,则事件不会分离。即使玩家不再拥有增益,该事件仍然会像他那样执行

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

我不明白的是,当从列表中删除
Buff
时,为什么事件不会自动取消跟踪。
Buff
仅存在于列表中,这是它的一个引用。移除后,事件不应该分离吗

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

谢谢。

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

该引用将继续存在,直到您调用player.damagetake-=player\u damagetake。你将Buff添加到activebuff中,这一事实只是为Buff添加了另一个引用,这在技术上是不必要的(但在我看来,这是一种很好的形式,因为我不喜欢让未引用的事件处理程序挂起)

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

  • 在player\u damagetake开始时,检查player.ActiveBuffs.Contains是否包含(此),如果不包含,请调用player.damagetake-=player\u damagetake并返回。这样做的缺点是,每次受到伤害时,你都会搜索整个buff列表

  • 使ActiveBuff成为一个ObservableCollection(或类似的东西),当从列表中删除buff时,它可以监听。当它们出现时,你可以自动调用buff.discover,这样开发者就不必记得调用它了

  • 我不明白的是,为什么当Buff从列表中移除时,事件不会自动取消跟踪

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

    有人想知道为什么在这里使用事件。为什么不让玩家中的代码遍历列表中的每个buff,并运行一些定义为接口一部分的方法,以损坏作为参数或返回值呢。那会更符合你的要求


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

    也许你在寻找类似弱事件模式的东西:你注意到的行为可能是内存泄漏的来源,原因相同:在手动将对象从事件中分离之前,对象不会被删除弱事件最终会起作用,但我的理解到事件将继续被调用,直到GC收集它,这对于实时游戏来说可能太晚了。丹尼尔卡斯特罗:是的,我一直在关注薄弱的事件,但要让它们在C#中正常工作似乎需要一些努力。此外,当他们从名单上删除的爱好者将不得不立即删除,因为凯尔罗文说。我想,结果是弱事件将不可用。这是一个好的观点。我不确定你是否必须等到GC收集它,我不这么认为,但正如我所说的,我不确定。关于实现,除了我已经发布的链接之外,如果您使用的是WPF,许多mvvm工具包都有类似的内容。例如,MVVM Light有一个用于弱事件的Messenger类。而且它很容易使用是的,我想我必须走定制收藏的道路。考虑到列表中的
    Update
    函数可以刷新所有的buff持续时间,我可能不得不这么做。此外,像buff列表一样重要的东西需要更多的特性。我想从
    IEnumerable
    继承就可以了。我只是更喜欢基于事件的编程。当玩家被击中时,会引发他或她被击中的事件。让相关类订阅
    PlayerDamaged
    事件,并对此类事件执行适当的逻辑,而不是在该方法中包含所有潜在代码。我不知道如何实现你所说的东西,像一个荆棘buff。
    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);
    }