2010-09-16 78 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

相关问题