【问题标题】:Is there a reason to remove a method from an event after it has been invoked in Silverlight?在 Silverlight 中调用事件后,是否有理由从事件中删除该方法?
【发布时间】:2012-06-11 16:31:56
【问题描述】:

最近我遇到越来越多的人编写类似以下代码:

private AsynchronousReader r;

public SynchronousReader()
{
    r = new AsynchronousReader();

    // My practice is to put this here
    // and then never remove it and never add it again
    // thus cleaning up the code and preventing constant add/remove.
    //r.ReadCompleted += this.ReadCompletedCallback;
}

private ReadCompletedCallback()
{
    // Remove the callback to "clean things up"...
    r.ReadCompleted -= this.ReadCompletedCallback;

    // Do other things
}

public Read()
{
    r.ReadCompleted += this.ReadCompletedCallback;

    // This call completes asynchronously and later invokes the above event
    r.ReadAsync();
    r.WaitForCompletion();
}

人们说这种做法比我上面指出的要好,并给出了 Silverlight 特有的几个原因。他们说它可以防止内存泄漏、线程问题,甚至是正常的做法。

我没有做过多少 Silverlight,但仍然这样做似乎很愚蠢。 是否有任何具体原因可以使用此方法,而不是在构造函数中一次性装配回调并在对象的生命周期内完成?

这就像我的例子一样简单。忽略它是一种将异步对象转换为同步对象的包装器这一事实。我只是对添加和删除事件的方式感到好奇。

【问题讨论】:

    标签: c# silverlight events


    【解决方案1】:

    在您提到它的情况下将其连接一次是有意义的,但对象(父和/或子)可能不会被垃圾收集,因为事件处理程序仍然引用它们。

    根据Marc Gavel here

    即如果我们有:

    publisher.SomeEvent += target.SomeHandler;
    

    然后“发布者”将保持“目标”活着,但“目标”不会保持 “出版商”还活着。

    要记住的更重要的一点可能是子对象的生命周期。 如果它与父级相同,则构造函数中的一次性订阅更有意义。如果它是动态的,您可能希望删除处理程序,因为我已经看到它们泄漏(导致多个回调)。

    注意:如果仅构造函数的方法会泄漏对象,我猜你总是可以在 Dispose() 中取消订阅,但我不能说我见过。

    【讨论】:

    • 在构造函数中放入r.ReadCompleted += this.ReadCompletedCallback;不是更方便吗?
    • 他通常不会订阅Read()中的事件
    • 好吧,无论如何我都会读。 stackoverflow.com/questions/298261/…
    • @HiTechMagic:我看到的方式是他通常在构造函数中订阅并且从不取消订阅。没被注释掉的代码是他在别人写的代码里找到的
    • 问题是最好的做法是将它放在构造函数中还是将其留在被调用的方法中,然后调用单独的异步方法并在调用回调后将其删除。我只想到的一点是,如果您按照此处实现的方式执行此操作,那么如果一个异步调用在另一个之前完成并且随后在刚刚完成的回调中删除了回调,那么两个竞相完成的异步调用将失败。注释掉的代码是我想要使用的做法,在我看来,实现的代码是糟糕/混乱的东西。
    【解决方案2】:

    听起来你有两个问题:

    1. 您正在尝试重用一个真正应该只使用一次的对象。
    2. 该对象需要正确清理。

    您实际上应该只使用 SynchronousReader 对象的一个​​实例一次(从而避免两个异步调用竞速而一个未能像您在其他地方提到的那样完成),或者您应该实现 IDisposable 以取消订阅该事件并防止内存泄漏。

    第三种解决方案可能是可行的:保留 SynchronousReader 的单个实例,但每次调用 SynchronousReader.Read 都会创建一个新的 AsynchronousReader 实例(而不是将其作为私有字段存储在实例中)。然后你可以保留上面的大部分你不喜欢的代码,但它们可以正确处理事件订阅。

    【讨论】:

    • 我的问题(在底部)表明包装器无关紧要。
    猜你喜欢
    • 1970-01-01
    • 2011-03-01
    • 2020-10-30
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多