最近,我遇到越来越多的人,他们的代码类似于以下内容:
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,但这样做仍然很愚蠢。 是否有任何特定原因可以使用此方法而不是仅仅在构造函数中绑定回调一次以及对象的生命周期?
这就像我可以做出我的榜样一样简单。忽略这一事实,它是一种将异步对象转换为同步对象的包装器。我只是对添加和删除事件的方式感到好奇。
答案 0 :(得分:1)
在你提到它的情况下, 有意义将它挂钩一次,但可能是对象(父对象和/或子对象)可能无法收集垃圾,因为事件处理程序仍然引用它们。 / p>
即。如果我们有:
publisher.SomeEvent += target.SomeHandler;
然后“发布者”将保持“目标”活着,但“目标”将不会保留 “出版商”活着。
要记住的更重要的一点可能是儿童对象的生命周期。 如果它与父级相同,那么构造函数中的一次性订阅更有意义。如果它是动态的,您可能会想要删除处理程序,因为我看到它们泄漏(导致多个回调)。
注意:如果仅使用构造函数方法泄露对象,您可以随时在Dispose()
中取消订阅,但我不能说我见过它。
答案 1 :(得分:-1)
听起来你有两个问题:
你实际上应该只使用一次SynchronousReader对象的实例(从而避免两个异步调用竞争,其中一个未能像你在其他地方提到的那样完成)或者你应该实现IDisposable以取消订阅事件并防止记忆泄漏。
第三种解决方案可能是:保留SynchronousReader的单个实例,但每次调用SynchronousReader.Read都会创建一个新的AsynchronousReader实例(而不是将其存储为实例中的私有字段)。然后你可以保留你不喜欢的大部分代码,但是正确处理事件订阅的代码。