1

可能重复:
事件处理程序是否会阻止垃圾收集的发生?

我有一个这样的 wp7 应用程序:

private void button1_Click(object sender, RoutedEventArgs e)
{
    GeoCoordinateWatcher watcher = new GeoCoordinateWatcher();
    watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
    watcher.Start();
}

void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
    Debug.WriteLine(e.Position.Timestamp.ToString());
}

单击两次按钮后,控制台将输出两次时间戳。但是观察者是一个局部变量!它出什么问题了?我怎么能破坏它?

4

2 回答 2

8

watcher is a local variable, but that doesn't affect the object necessarily. You've asked the GeoCoordinateWatcher to start - I'd expect it to maintain a reference to itself, effectively, or stash one somewhere appropriate.

It sounds like either you ought to disable the button once it's clicked, or you need to keep the watcher in an instance variable so that you can dispose of the old one and create a new one. (I'm not sure why that would be useful though.)

EDIT: As there are two incorrect answers here, let me just clear something up... an event publisher (the watcher in this case) has references to the handler delegates. If those delegates refer to instance methods (as it does in this case) then there's a reference to an instance of the type containing that method:

 Event publisher => delegate => instance of type with handler method

That means that as long as the publisher isn't garbage collected (and the event handler still exists), the instance associated with the delegate can't be collected. It doesn't prevent the publisher itself from being garbage collected.

In other words, if GeoCoordinateWatcher didn't do something "special" (probably in the Start method) it could be garbage collected. There's no implicit reference from an event handler to the event publisher which prevents it from being garbage collected that way round.

于 2012-06-12T07:30:03.877 回答
-2

GC 实际上不会收集watcher,因为事件仍然被分配(这意味着GeoCoordinateWatcher实例仍然被引用,因此没有被 GC 收集)。即使局部变量超出范围,实例仍然存在。

分离事件处理程序watcher_PositionChanged,事情按预期工作。如果不这样做,则GeoCoordinateWatcher每次单击按钮时都会有一个新实例,并且每个按钮都会在位置更改时调用该事件。

这是在本地创建实例/分配事件时有时会出现各种奇怪问题的原因。在像您这样的情况下,有两种可能的解决方案:

  1. 创建一个实例变量,并确保只做一次
  2. 确保在创建新实例之前正确处理旧实例(依赖垃圾收集器)
于 2012-06-12T07:34:53.313 回答