对于INotifyPropertyChanged的可放弃用户,是否存在安全的非泄漏模式?

时间:2011-09-16 16:39:18

标签: events memory-leaks weak-events

INotifyPropertyChanged的使用者是否有任何模式可以避免内存泄漏,即使在特定的INotifyPropertyChanged对象的生命周期内可能会创建任意数量的使用者实例但没有更改任何对象的属性的情况下(因此通知发射)?事件发布者可以通过一些反思技巧来实现弱事件;有没有可行的用户方弱事件模式?

如果事件合同要求事件发布者必须允许事件订阅者随时从任何线程取消订阅而不会无限期地阻止,那么事件订阅者就有可能拥有实际上“感兴趣”的对象。订阅者保留对包装器对象的引用,并使包装器对象覆盖Finalize()以告知订阅者对象取消订阅。不幸的是,即使订阅者通过Finalize()发现它应该取消其订阅,.net事件合同也不要求发布事件的对象必须允许它们在终结器内安全地处理。实际上,C#的默认事件实现实际上从终结器中调用是不安全的(当前实现获取对发布订阅的对象的锁定;如果锁仅用于订阅和取消订阅,那将不是问题,但不能保证锁定在某个任意长度的时间内不会被用于其他目的)。早期的实现更糟糕:如果一个类试图订阅或取消订阅它自己的事件,那么订阅和取消订阅根本就不是线程安全的。

如果知道INotifyPropertyChanged对象是某个以线程安全方式实现其事件的特定类(对于预订,获取锁,然后使用Interlocked.Exchange自旋循环;对于取消订阅,使用自旋循环,如果可用,将获取锁,但是无论锁是否可用,都将尝试Interlocked.CompareExchange)可以安全地删除终结器中的事件处理程序。如果一个人知道该对象将以一个显着的频率提升事件,那么可以从事件中删除处理程序(尽管我不确定.net事件契约是否也要求安全)。是否存在任何通用解决方案,无论何种类型的INotifyPropertyChanged实施者都可以观看?

修改 - 澄清

这个想法不是一个对象会取消订阅它自己的终结器,而是那些对事件的效果感兴趣的对象将保存对包装器对象的引用,事件处理本身不能保存对象。参考。例如,假设目标是计算使用特定事件名称字符串引发PropertyChanged事件的次数。可以有一个PropertyChangeCounter对象,它持有对PropertyChangeCounter.Internals对象的引用;后一个对象将保存事件订阅和更改计数。 PropertyChangeCounter对象的ChangeCount属性将返回嵌套的PropertyChangeCounter.Internals ChangeCount的值。一旦没有外人对其进行引用,包装器对象就有资格进行最终化,并且其终结器可以在PropertyChangeCounter.Internals对象中调用unsubscribe方法。

0 个答案:

没有答案