问题
In C#/.NET, is there any way to get a notification before the object pointed to by a weak reference is destructed? Basically, I want to allow an object to be collected, but do something right before the object is destroyed, without modifying code to add destructors (since I won't know exactly what types of objects will be sued with my code).
Thanks, Robert
回答1:
.Net 4.0 has the solution you need: ConditionalWeakTable. Here is a short program that demonstrates the idea. (discussed here as well)
using System;
using System.Runtime.CompilerServices;
namespace GCCollectNotification
{
class ObjectToWatch { }
class Notifier
{
public object ObjectToWatch { get; set; }
~Notifier() { Console.WriteLine("object is collected"); }
}
class Program
{
private ConditionalWeakTable<object, Notifier> map
= new ConditionalWeakTable<object, Notifier>();
public void Test()
{
var obj = new ObjectToWatch();
var notifier = map.GetOrCreateValue(obj);
notifier.ObjectToWatch = obj;
}
static void Main(string[] args)
{
new Program().Test();
GC.Collect();
GC.WaitForPendingFinalizers();
// "object is collected" should have been printed by now
Console.WriteLine("end of program");
}
}
}
回答2:
No there is no way to achieve this functionality.
After a bit of speculation, I don't believe it's possible to implement a feature in the manner you are describing.
Consider that at the point the object held by a WeakReference is collected, there are no more references (hence it's collectable). For an event to have any use to you it would need to provide the object as part of the event. This means that the reference has gone from collectable to not-collectable. There is nothing stopping the handling code from retaking a reference on that object. Hence the object can no longer be considered collectable. The CLR would need to make a second pass on the object to re-ensure it was collectable.
You can see how the second time around the event could not be raised because it would lead to uncollectable objects.
It would be a misuse of naming to claim this event was raised just before an object was collected. Simply because any handler could prevent this from being collected by establishing a new reference to the object. Instead it would have to be "ObjectMaybeAboutToBeCollected". This probably won't give you the behavior you're looking for.
回答3:
You can't do that. However what you can do is to watch when a GC is approaching ( there are new GC APIs in CLR v3.5Sp1 that allows you to do so, GCNotifications )
回答4:
Your question doesn't make sense to me. Where is the code that's going to be called supposed to reside? Given that the weak references will be nulled before the referenced object is destroyed, it doesn't make sense for it to be part of the class that referenced the about-to-be destroyed object. And there's already code in the referenced object that's called before the object is destroyed - that's the destructor.
What's the actual design problem you want to solve? There may be a better way.
回答5:
For what you are describing, finalizers would be a way better approach.
回答6:
It would be possible to have semantics similar to what you describe if a weak reference with a notifier were regarded similarly to an object with a finalizer, which is to say that when the object was considered to no longer be of interest to anybody, it would be queued for finalization and notification; the queue entry would be considered a live reference, so the object would not actually be collected until it was acted upon.
Since that isn't possible, the best feasible approach might probably be to have all "I'm interested in this object" references point to a lightweight wrapper object which would in turn point to the real object, and have the "weak" references point to a different wrapper which would also point to the real object. The first wrapper should hold a reference to the second, but not vice versa. The first wrapper should have a finalizer which will trigger appropriate code when it goes out of scope.
Unfortunately, I haven't seen any complete implementations of such a strategy. There are some important caveats to consider. Among them: (1) finalizers should never wait on locks, nor do anything that could throw an exception; (2) code which accesses other objects which might have gone out of scope must be prepared for the possibility that they may have already been finalized, be in the process of being finalized, be awaiting finalization, or still have live references elsewhere; (3) if a finalizer stores a rooted reference to a finalizable object which has been found eligible for garbage collection, such an object may be finalized even though the live reference exists.
来源:https://stackoverflow.com/questions/1145529/c-notification-before-weakreference-is-collected