2010-09-16 59 views
2

考慮下面的代碼:方法範圍變量的事件會發生什麼?

public class Bar { 
    Foo foo; 
    void Go() { 
     foo = new Foo(); 
     foo.Send(...); 

     foo.Dispose(); 
     foo = null; 
    } 
} 

public class Foo : IDisposable { 
    public void Send(byte[] bytes) { 
     SocketAsyncEventArgs args = new SocketAsyncEventArgs(); 
     args.SetBuffer(bytes, 0, bytes.Length); 
     args.UserToken = socket; 
     args.RemoteEndPoint = endPoint; 
     args.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted); 

     socket.SendAsync(args); 
    } 

    private void OnSendCompleted(object sender, SocketAsyncEventArgs e) { 
     Debug.WriteLine("great"); 
    } 

    public void Dispose() { 
     // 
    } 
} 

所以Bar類運行初始化方法,該方法實例化Foo類和火災關閉Send方法,然後破壞了富實例。 Send方法同時實例化方法級別SocketAsyncEventArgs,設置Completed事件,然後觸發SendAsync方法。

假設SendAsync在Foo實例設置爲null之後完成,那麼事件處理程序會發生什麼?它還在燃燒嗎?如果我不希望它激發,我該如何正確地清理Foo類,知道方法級別變量會從事件中產生。

回答

3

是的,它仍然會着火。將變量設置爲null不會觸發垃圾回收或類似的東西。它只是將變量設置爲null。 (區分變量和實例是很重要的,沒有「將實例設置爲null」這樣的概念,如果我把我的家庭地址寫在一張紙上,然後再次擦掉,這並不會破壞我的)

聽起來好像你可能想要你的Dispose方法「記住」該對象已被清理,然後如果在處理後調用OnSendCompleted,就忽略它。或者,跟蹤任何「在飛行中的請求」並取消它們在Dispose ...注意到一些請求可能會完成您將取消整個地段。

還有一點要注意:不是顯式調用Dispose(),你應該總是使用using聲明,這將確保Dispose()被稱爲然而using語句結束(例如,用一個例外)。

1

如何通過在您的OnSendCompleted方法中使用- =來嘗試解除事件?

e.Completed -= new EventHandler<SocketAsyncEventArgs>(OnSendCompleted); 
+0

這樣做是否「安全」?它應該不會導致寫好的add-handler/remove-handler/raise-event代碼出現問題,但我不知道假定刪除事件處理程序不會被認爲是「安全」的,例如需要獲取可以在事件處理程序期間保持的鎖。有什麼明確說明這樣的假設被認爲是「安全的」,並且任何違反該假設的代碼都應該被認爲是「破碎的」? – supercat 2011-02-01 19:50:48