我有一个DLL SomeLib.dll
,其中包含DeleteHandler
个对象:
public class DeleteHandler
{
private _handlerToServerObj;
public DeleteHandler()
{
_handlerToServerObj = new HandlerToServerObj(/* ... */);
_handlerToServerObj.OnDelete += new OnDeleteEventHandler(OnDeleteEH);
}
public void Delete(string id)
{
_handlerToServerObj.Delete(id);
}
private void OnDeleteEH(string id)
{
//
}
}
工作原理:
_handlerToServerObj.Delete(id)
正在向服务器发送消息,并且该呼叫立即返回; OnDelete
事件。此库通常由WinForms
应用程序使用。
通常情况下,我希望Delete()
方法在服务器确实删除项目后返回 (即OnDelete
事件被触发,因此,执行OnDeleteEH
。
我尝试使用ManualResetEvent
,但没有成功(即永远不会调用OnDeleteEH
):
private ManualResetEvent _waitHandle = new ManualResetEvent(false);
public void Delete(string id)
{
_waitHandler.Reset();
_handlerToServerObj.Delete(id);
_waitHandle.WaitOne();
}
private void OnDeleteEH(string id)
{
//
_waitHandle.Set();
}
或者:
private ManualResetEvent _waitHandle = new ManualResetEvent(false);
public void Delete(string id)
{
_waitHandler.Reset();
Thread thread = new Thread(PrivateDelete);
thread.Start(id);
_waitHandle.WaitOne();
}
private void PrivateDelete(string id)
{
_handlerToServerObj.Delete(id);
}
private void OnDeleteEH(string id)
{
//
_waitHandle.Set();
}
这个设计有效吗?如果是的话,我在实施过程中犯的错误是什么?如果不是,请你建议更正?
[编辑1]
纠正了与代码相关的一些错误。
答案 0 :(得分:4)
你在方法中隐藏等待句柄,这导致你等待一个永远不会被设置的句柄。
您需要使用实例字段,而不是在_waitHandle
中声明名为Delete
的新变量。
当然,如果使用匿名事件处理程序而不是其他方法,则可以简化代码:
public void Delete(string id)
{
ManualResetEvent waitHandle = new ManualResetEvent(false);
_handlerToServerObj.OnDelete += () => waitHandle.Set();
_handlerToServerObj.Delete(id);
waitHandle.WaitOne();
}
如果你像这样使用一个闭包,那么你根本不需要把柄作为一个实例字段。
说完所有这些后,如果你在桌面UI应用程序的上下文中使用它,你可能不会想要有一个阻塞方法;你可能想要异步地做这样的工作,而不是同步。如果在UI线程中调用,您将阻止UI线程,并创建一个新的工作线程,以便它可以在一些异步IO操作上花费所有时间阻塞,这简直是浪费。虽然可能存在一些您真正想要等待此事件的情况,但请花点时间确保它适合您的具体情况。