委托可以防止对象被垃圾收集吗?

时间:2016-05-27 08:17:50

标签: c# garbage-collection

我说我的课程定义为:

class MyWrapper<T> where T : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  private void OnPropertyChange(String propname)
  {
    handlePropertyChanged(this, new PropertyChangedEventArgs(propname));
  }

  private void handlePropertyChanged(object sender, PropertyChangedEventArgs e)
  {
      var handler = PropertyChanged;
      if (handler != null)
      {
          handler(sender, e);
      }
  }

  private T _backing;
  public MyWrapper(T backing)
  {
    _backing=backing;
    _backing.PropertyChanged+=handlePropertyChanged;
  }

  ...Reasons for wrapping the class...
}

此类在后备对象上的PropertyChanged事件上设置委托。 根据我的理解,这个委托有一个指向MyWrapper实例的指针。这是否意味着MyWrapper的实例的生命周期不会短于烘焙对象?

如果是这样,有办法解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

是的,另一个属性对事件句柄的引用会阻止MyWrapper类实例被垃圾回收。只有当释放对处理程序的所有引用时(例如,当这些实例也符合GC条件时),才能从内存中释放MyWrapper实例。

此问题类似于之前发布的问题:Do event handlers stop garbage collection from occuring?

修改 要回答您对该代表的评论,请将handlePropertyChanged指定为backing的代理,该代理会创建对MyWrapper的外部引用。因此,在删除该引用之前,MyWrapper将不会被GC。

有几种方法可以解决这个问题:

  1. 使用弱引用:https://msdn.microsoft.com/en-us/library/system.weakreference(v=vs.110).aspx
  2. 一旦不再需要,就删除对委托/事件的引用。

答案 1 :(得分:1)

如果你真的想保留一个没有阻止GC的引用,那么看一下弱引用。这些允许您保持对对象的引用,只要它存在(您总是需要明确检查对象是否仍然存在并提取“真实”,强引用)。

对于代表,WeakEvent是合适的。

但是,我也建议采用另一种方法。如果事件处理程序确实没有做任何事情(如示例代码中所示),则可以完全跳过它,并像这样声明PropertyChanged

public event PropertyChanged
{
    add { _backing.PropertyChanged += value; }
    remove { _backing.PropertyChanged -= value; }
}

或者,如果处理程序很重要(例如,它转换输入等),您可以考虑使用一个显式的dispose模式来取消注册任何事件处理程序:

public void Dispose() { _backing.PropertyChanged -= handlePropertyChanged; }

完成使用包装器对象后,只需调用Dispose(或者,如果有固定范围,请使用using)。这是简化的 - 一个适当的配置模式有点复杂,但如果你不处理非托管资源则不是必需的。