我有这个实现PreloadClient
的对象IDisposable
,我想处理它,但在异步方法完成调用之后......这没有发生
private void Preload(SlideHandler slide)
{
using(PreloadClient client = new PreloadClient())
{
client.PreloadCompleted += client_PreloadCompleted;
client.Preload(slide);
}
// Here client is disposed immediately
}
private void client_PreloadCompleted(object sender, SlidePreloadCompletedEventArgs e)
{
// this is method is called after a while,
// but errors are thrown when trying to access object state (fields, properties)
}
那么,任何想法或解决方法??
答案 0 :(得分:11)
您不应该使用using
构造,而是在不再需要它们时处置它们:
// keep a list of strong references to avoid garbage collection,
// and dispose them all in case we're disposing the encapsulating object
private readonly List<PreloadClient> _activeClients = new List<PreloadClient>();
private void Preload(SlideHandler slide)
{
PreloadClient client = new PreloadClient();
_activeClients.Add(client);
client.PreloadCompleted += client_PreloadCompleted;
client.Preload(slide);
}
private void client_PreloadCompleted(object sender,
SlidePreloadCompletedEventArgs e)
{
PreloadClient client = sender as PreloadClient;
// do stuff
client.PreloadCompleted -= client_PreloadCompleted;
client.Dispose();
_activeClients.Remove(client);
}
在这种情况下,您必须在处置主类时处置所有客户端:
protected override Dispose(bool disposing)
{
foreach (PreloadClient client in _activeClients)
{
client.PreloadCompleted -= client_PreloadCompleted;
client.Dispose();
}
_activeClients.Clear();
base.Dispose(disposing);
}
请注意,此实现不是线程安全的
_activeClients
列表必须为made thread-safe,因为您的PreloadCompleted
方法是从其他线程调用的try
/ finally
块可能是个好主意,以确保在所有情况下都可以处置该对象答案 1 :(得分:3)
为什么不将客户端部署在回调中?
答案 2 :(得分:1)
我有一些想法:
答案 3 :(得分:0)
如果有事件处理程序被注册,则在有可能被调用的事件时,您无法真正处置该对象。你最好的选择是让包含类一次性使用将客户端存储在类变量中,以便在包含类时使用。
像
这样的东西class ContainingClass : IDisposable
{
private PreloadClient m_Client;
private void Preload(SlideHandler slide)
{
m_Client = new PreloadClient())
m_Client.PreloadCompleted += client_PreloadCompleted;
m_Client.Preload(slide);
}
private void client_PreloadCompleted(object sender, SlidePreloadCompletedEventArgs e)
{
}
public void Dispose()
{
if (m_Client != null)
m_Client.Dispose();
}
}
答案 4 :(得分:0)
好吧,处理一个对象用于杀死你不想要的资源,直到GC(最终)到来并收集你的对象。您的dispose方法是否会在client_PreloadCompleted
中杀死您需要的任何内容?
当所有预期的回调都发生时,您可以让对象自行处理:为您期望的每个回调保留一个“引用计数器”,并在每次回调发生时递减 - 在回调处理程序结束时检查null并处理如此。
其他解决方法:不要担心IDisposable
。 GC将收集您的对象。您可能不希望回调处理程序(可能不会被触发)具有临界状态。它(回调)应该只在打开它时打开它需要的任何资源然后关闭它们。
答案 5 :(得分:0)
异步等待和确定性处理不能很好地混合。如果你能找到一种方法来分割代码,使得一次性东西进入一个类,而事件进入另一个类,这将使一切变得更简单。
答案 6 :(得分:0)
为什么不使用client_PreloadCompleted
方法进行处理?
类似于thecoop提供的内容,只需使用上述方法中的Dispose
调用,就可以从客户端对象中访问所有需要的数据。
编辑:我认为这也是orialmog提供的。