2013-10-07 47 views
1

我附加到第三方,長時間生活已刪除的事件發佈程序,最終由於事件處理程序而使我的可能的短期對象保持活動狀態。 Deleted事件很可能永遠不會觸發,我只需要處理事情。不清楚從何處取消已刪除的事件,因此我想要對其進行弱引用,以便我的對象可以被GC'd。C#使用弱引用聆聽第三方長時間生活事件

我已經看到了很多非常複雜的方法來創建弱事件處理程序,但下面的代碼片段似乎可以做到這一點,至少在提供的測試代碼片段中。這是瘋了還是可以工作?

http://diditwith.net/CommentView,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx「的首種嘗試」下說,類似的片段「(...)沒有足夠強大的與事件(...)用」,爲什麼不呢?)

public static class WeakEvent 
{ 
    private class WeakEventHolder<TArgs> where TArgs : EventArgs 
    { 
     private readonly WeakReference _handler; 

     public WeakEventHolder(Action<object, TArgs> handler) 
     { 
      _handler = new WeakReference(handler); 
     } 

     public void Handle(object sender, TArgs args) 
     { 
      Action<object, TArgs> handler = (Action<object, TArgs>)_handler.Target; 
      if (handler != null) 
       handler(sender, args); 
     } 
    } 

    public static EventHandler MakeHandler(Action<object, EventArgs> handler) 
    { 
     return new WeakEventHolder<EventArgs>(handler).Handle; 
    } 
} 

測試類

[TestFixture] 
public class Tests 
{ 
    public class Publisher 
    { 
     public EventHandler Event; 

     public void Raise() 
     { 
      if (Event != null) 
       Event(this, EventArgs.Empty); 
     } 
    } 

    public class Target 
    { 
     public Target(Publisher publisher) 
     { 
      publisher.Event += WeakEvent.MakeHandler(HandleEvent); 
     } 

     public void HandleEvent(object sender, EventArgs args) 
     { 
      System.Diagnostics.Trace.WriteLine("HandleEvent"); 
     } 
    } 

    [Test] 
    public void Test() 
    { 
     Publisher publisher = new Publisher(); 
     WeakReference wref = new WeakReference(new Target(publisher)); 
     GC.Collect(); 

     publisher.Raise(); 

     Assert.False(wref.IsAlive); 
    } 
} 

回答

1

因爲Action<object, TArgs> handler也許垃圾回收它的目標之前。下面是一個暴露問題的單元測試:

public class Bar 
{ 
    public void Foo(object sender, EventArgs args) 
    { 
    } 
} 

[Test] 
public void ActionIsNotGCedBeforeTarget() 
{ 
    Bar bar = new Bar(); 
    Action<object, EventArgs> action = bar.Foo; 
    WeakReference weakRef = new WeakReference(action); 
    action = null; 
    GC.Collect(); 

    Assert.IsTrue(weakRef.IsAlive); // Will be false 
}