Is there any safe non-leaky pattern for an abandonable user of an INotifyPropertyChanged?
Is there any pattern by which a consumer of an INotifyPropertyChanged can avoid memory leaks even in circumstances where an arbitrary number of instances of the consumer may be created during the lifetime of a particular INotifyPropertyChanged object, without any of that object's properties being changed (and thus notifications firing)? It's possible for an event publisher to implement weak events with some Reflection trickery; is there any workable subscriber-side weak event pattern?
If the Event contract required that an event publisher must allow event subscribers to unsubscribe at any time, from any thread, without blocking indefinitely, then it would be possible for an event subscriber to have objects that were actually "interested" in the subscriber keep a reference to a wrapper object, and have the wrapper object override Finalize() to tell the subscriber object to unsubscribe. Unfortunately, even if subscriber discovers via Finalize() that it should cancel its subscription, the .net Event contract does not require that objects which publish events must allow them to be safely disposed from within a finalizer. Indeed, the default event implementation for C# is in fact not safe to call from within a finalizer (the current implementation acquires a lock on the object publishing the subscription; if the lock were only used for subscription and unsubscription that wouldn't be a problem, but there's no guarantee that the lock won't be held for some other purpose for some arbitrary length of time). Earlier implementations were worse: if a class attempted to subscribe or unsubscribe to its own events, subscription and unsubscription wouldn't be thread-safe at all.
If one knew that the INotifyPropertyChanged object was some particular class which implemented its events in thread-safe manner (for subscription, acquire a lock 开发者_如何学Pythonand then use an Interlocked.Exchange spin-loop; for unsubscription, use a spin-loop which will acquire the lock if available but will try the Interlocked.CompareExchange whether the lock is available or not) one could safely remove the event handler in a finalizer. If one knew that the object would be raising the event with some significant frequency, one could perhaps remove the handler from within the event (though I'm not sure the .net event contract requires that to be safe either). Is there any general-purpose solution which will work no matter what type of INotifyPropertyChanged implementer one is given to watch?
EDIT--Clarification
The idea isn't that an object would unsubscribe from its own finalizer, but rather that objects which were interested in the effects of the event would hold references to a wrapper object, to which the event-handling itself would not hold a reference. For example, suppose the goal was to count how many times a PropertyChanged event was raised with a particular event-name string. One could have a PropertyChangeCounter object, which held a reference to a PropertyChangeCounter.Internals object; the latter object would hold the event subscription and the change count. The ChangeCount property of the PropertyChangeCounter object would return the value of the nested PropertyChangeCounter.Internals ChangeCount. The wrapper object would become eligible for finalization once no outsider held a reference to it, and its finalizer could call an unsubscribe method in the PropertyChangeCounter.Internals object.
精彩评论