如何处置包含事件的局部变量

时间:2012-06-12 07:21:31

标签: c#

  

可能重复:
  Do event handlers stop garbage collection from occuring?

我有一个像这样的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());
}

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

2 个答案:

答案 0 :(得分:8)

watcher是一个局部变量,但这不一定会影响对象。您已经要求GeoCoordinateWatcher开始 - 我希望它能够有效地保留对自身的引用,或者在适当的位置存储它。

听起来要么你应该在点击按钮后禁用按钮,你需要将观察者保持在一个实例变量中,以便你可以处理旧的一个并创建一个新的。 (我不确定为什么那会有用。)

编辑:由于这里有两个不正确的答案,让我先澄清一下......事件发布者(在这种情况下是观察者)引用了处理程序代理。如果这些委托引用了实例方法(就像在这种情况下那样),那么就会引用包含该方法的类型的实例:

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

这意味着只要发布者不是垃圾回收(并且事件处理程序仍然存在),就无法收集与该委托关联的实例。它不会阻止发布者自己被垃圾收集。

换句话说,如果GeoCoordinateWatcher没有执行“特殊”操作(可能在Start方法中),则可以进行垃圾回收。从事件处理程序事件发布者没有隐式引用,这会阻止它以那种方式进行垃圾回收。

答案 1 :(得分:-2)

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

watcher_PositionChanged中分离事件处理程序,事情按预期工作。如果不这样做,则每按一次按钮就会有一个GeoCoordinateWatcher的新实例,并且当位置发生变化时,每个实例都会调用该事件。

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

  1. 创建一个实例变量,并确保只执行一次
  2. 确保在创建新实例之前正确处置旧实例(依赖于垃圾收集器)