C#:收集WeakReference之前的通知?

在C#/ .NET中,有没有办法在弱引用指向的对象被破坏之前获得通知? 基本上,我想允许收集一个对象,但在对象被销毁之前做一些事情,而不修改代码来添加析构函数(因为我不知道究竟什么类型的对象将被我的代码起诉)。

谢谢,罗伯特

你不能这样做。 但是,您可以做的是观察GC何时接近(CLR v3.5Sp1中有新的GC API允许您这样做,GCNotifications)

没有办法实现这个function。

经过一番猜测后,我认为不可能以您描述的方式实现function。

考虑到收集WeakReference持有的对象时,没有更多的引用(因此它是可收集的)。 对于对您有用的事件,它需要提供对象作为事件的一部分。 这意味着引用已从可收集到不可收集。 没有什么能阻止处理代码重新获得对该对象的引用。 因此,该对象不再被视为可收集。 CLR需要对对象进行第二次传递以重新确保它是可收集的。

您可以看到第二次无法引发事件,因为它会导致无法收集的对象。

声称在收集对象之前引发此事件将是对命名的误用。 只是因为任何处理程序都可以通过建立对该对象的新引用来防止这种情况被收集。 相反,它必须是“ObjectMaybeAboutToBeCollected”。 这可能不会给你你正在寻找的行为。

.Net 4.0有你需要的解决方案: ConditionalWeakTable 。 这是一个简短的程序,展示了这个想法。 ( 这里也讨论过)

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 map = new ConditionalWeakTable(); 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"); } } } 

你的问题对我没有意义。 将被称为驻留的代码在哪里? 假定在引用的对象被销毁之前弱引用将被清零,那么它成为引用即将被销毁的对象的类的一部分是没有意义的。 并且在对象被销毁之前已经调用了引用对象中的代码 – 这就是析构函数。

您想要解决的实际设计问题是什么? 可能有更好的方法。

对于您所描述的内容,终结器将是一种更好的方法。

如果带有通知程序的弱引用被视为与具有终结符的对象类似,则可能具有与您描述的语义类似的语义,也就是说当对象被认为不再对任何人感兴趣时,它将会排队等待最终确定和通知; 队列条目将被视为实时引用,因此在对象被采取行动之前,实际上不会收集该对象。

由于这是不可能的,最好的可行方法可能是让所有“我对这个对象感兴趣”引用指向一个轻量级的包装器对象,它反过来指向真实对象,并具有“弱”引用指向一个不同的包装器,它也指向真实的对象。 第一个包装器应该保持对第二个的引用,但反之则不然。 第一个包装器应该有一个终结器,当它超出范围时会触发适当的代码。

不幸的是,我还没有看到这种策略的任何完整实现。 需要考虑一些重要的警告。 其中:(1)终结者不应该等待锁定,也不应做任何可能引发exception的事情; (2)访问可能已经超出范围的其他对象的代码必须准备好它们可能已经完成,正在最终确定,等待最终确定,或者仍然在其他地方有实时参考的可能性; (3)如果终结器存储对已被发现有资格进行垃圾收集的可终结对象的有根引用,则即使存在实时引用,也可以最终确定这样的对象。