如何释放包含事件的局部变量

本文关键字:包含 事件 局部变量 释放 何释放 | 更新日期: 2023-09-27 18:37:02

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

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

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

如何释放包含事件的局部变量

watcher是一个

局部变量,但这不一定会影响对象。您已经要求GeoCoordinateWatcher开始 - 我希望它有效地维护对自身的引用,或者将一个藏在适当的地方。

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

编辑:由于这里有两个不正确的答案,让我澄清一些事情......事件发布者(在本例中为观察程序)具有对处理程序委托的引用。如果这些委托引用实例方法(在本例中也是如此),则引用包含该方法的类型实例

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

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

换句话说,如果GeoCoordinateWatcher没有做一些"特殊"的事情(可能在Start方法中),它可能会被垃圾回收。事件处理程序没有对事件发布者的隐式引用,以防止它以这种方式进行垃圾回收。

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

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

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

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