如何使用 Task<T> 引发事件并等待事件完成
How to use Task<T> raising an event and waiting for event to be finished
我有以下场景:
正在请求启动网络服务的客户端
public bool Start(MyProject project, string error)
方法中接收客户端调用的web服务
public event EventHandler<StartEventArgs> startEvent;
public bool Start(MyProject project, string error)
{
Task<bool> result = StartAsync(project, error);
return result.Result;
}
protected virtual void OnStart(StartEventArgs e)
{
// thread safe trick, snapshot of event
var se = startEvent;
if (se != null)
{
startEvent(this, e);
}
}
private Task<bool> StartAsync(MyProject project, string error)
{
var taskCompletion = new TaskCompletionSource<bool>();
this.startEvent += (p, e) => taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false);
this.OnStart(new StartEventArgs(project, error));
return taskCompletion.Task;
}
正在订阅位于 Web 服务中的事件的应用程序:
app.Start += EventHandler(App_Start)
private bool App_Start()
{
// does something
returns true/false
}
我希望网络服务在任务中触发事件,然后等待app.exe中的函数完成,然后return在这里通知用户任务已成功完成。
我不确定该怎么做,但理论上它看起来像这样:
Task<bool> startTask = Task.Factory.StartNew(() => { OnStart() });
startTask.WaitAll(); // I think this is what I would need to for 4.0
return startTask.Result
我希望我的描述足够让别人看到我正在尝试做的事情。我希望该服务不必了解有关客户端的任何信息,只需 运行 任务,一旦事件完成执行,就会回到这一点,并 return 向客户端表示一个布尔值 success/failure.
这可能吗?还是我采取了错误的方法?
更新:
显然 OnStart 不是一个事件,所以我该怎么做你要向我解释的事情?
您可以通过 TaskCompletionSource<T>
将描述基于事件的异步模式的事件包装到 Task<T>
中。基本模式通常类似于:
Task<bool> StartAsync()
{
var tcs = new TaskCompletionSource<bool>();
// When the event returns, set the result, which "completes" the task
service.OnStarted += (o,e) => tcs.TrySetResult(e.Success);
// If an error occurs, error out the task (optional)
service.OnStartError += (o,e) => tcs.TrySetException(e.Exception);
// Start the service call
service.Start();
// Return the Task<T>
return tcs.Task;
}
所以我想我现在明白需要如何完成这就是我现在正在做的。
服务代码:
public void SetStartTask(Task<bool> startTask)
{
this.startTask = startTask;
}
public bool Start(RtProjectInfo project, string error)
{
StartEventArgs args = new StartEventArgs(project, error);
OnStart(args);
return startTask.Result;
}
protected virtual void OnStart(StartEventArgs e)
{
// thread safe trick, snapshot of event
var se = startEvent;
if (se != null)
{
startEvent(this, e);
}
}
public void StartFinished(MyProject project, string error)
{
OnStartFinish(new StartEventArgs(project, error));
}
protected virtual void OnStartFinish(StartEventArgs e)
{
var sef = startFinished;
if (sef != null)
{
startFinished(this, e);
}
}
这是一个测试客户端实现
public void Start_Event(object sender, StartEventArgs e)
{
Task<bool> startTask = StartAsync();
service.SetStartTask(startTask);
DoOtherWork();
DoOtherWork();
DoOtherWork();
}
private Task<bool> StartAsync()
{
var taskCompletion = new TaskCompletionSource<bool>();
service.startFinished += (p, e) =>
{
taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false);
};
return taskCompletion.Task;
}
private void DoingWork()
{
for(int i = 0; i < 100; ++i)
{
}
service.StartFinished(project, error);
}
private void DoOtherWork()
{
for (int i = 0; i < 100000; ++i)
{
}
}
很明显,每当有人调用 DoingWork() 时,都会收到事件,大家都很高兴!如果有人有任何更好的建议请提供,因为我只是在学习如何正确使用 TPL。
我有以下场景:
正在请求启动网络服务的客户端
public bool Start(MyProject project, string error)
方法中接收客户端调用的web服务
public event EventHandler<StartEventArgs> startEvent; public bool Start(MyProject project, string error) { Task<bool> result = StartAsync(project, error); return result.Result; } protected virtual void OnStart(StartEventArgs e) { // thread safe trick, snapshot of event var se = startEvent; if (se != null) { startEvent(this, e); } } private Task<bool> StartAsync(MyProject project, string error) { var taskCompletion = new TaskCompletionSource<bool>(); this.startEvent += (p, e) => taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false); this.OnStart(new StartEventArgs(project, error)); return taskCompletion.Task; }
正在订阅位于 Web 服务中的事件的应用程序:
app.Start += EventHandler(App_Start) private bool App_Start() { // does something returns true/false }
我希望网络服务在任务中触发事件,然后等待app.exe中的函数完成,然后return在这里通知用户任务已成功完成。
我不确定该怎么做,但理论上它看起来像这样:
Task<bool> startTask = Task.Factory.StartNew(() => { OnStart() });
startTask.WaitAll(); // I think this is what I would need to for 4.0
return startTask.Result
我希望我的描述足够让别人看到我正在尝试做的事情。我希望该服务不必了解有关客户端的任何信息,只需 运行 任务,一旦事件完成执行,就会回到这一点,并 return 向客户端表示一个布尔值 success/failure.
这可能吗?还是我采取了错误的方法?
更新: 显然 OnStart 不是一个事件,所以我该怎么做你要向我解释的事情?
您可以通过 TaskCompletionSource<T>
将描述基于事件的异步模式的事件包装到 Task<T>
中。基本模式通常类似于:
Task<bool> StartAsync()
{
var tcs = new TaskCompletionSource<bool>();
// When the event returns, set the result, which "completes" the task
service.OnStarted += (o,e) => tcs.TrySetResult(e.Success);
// If an error occurs, error out the task (optional)
service.OnStartError += (o,e) => tcs.TrySetException(e.Exception);
// Start the service call
service.Start();
// Return the Task<T>
return tcs.Task;
}
所以我想我现在明白需要如何完成这就是我现在正在做的。
服务代码:
public void SetStartTask(Task<bool> startTask)
{
this.startTask = startTask;
}
public bool Start(RtProjectInfo project, string error)
{
StartEventArgs args = new StartEventArgs(project, error);
OnStart(args);
return startTask.Result;
}
protected virtual void OnStart(StartEventArgs e)
{
// thread safe trick, snapshot of event
var se = startEvent;
if (se != null)
{
startEvent(this, e);
}
}
public void StartFinished(MyProject project, string error)
{
OnStartFinish(new StartEventArgs(project, error));
}
protected virtual void OnStartFinish(StartEventArgs e)
{
var sef = startFinished;
if (sef != null)
{
startFinished(this, e);
}
}
这是一个测试客户端实现
public void Start_Event(object sender, StartEventArgs e)
{
Task<bool> startTask = StartAsync();
service.SetStartTask(startTask);
DoOtherWork();
DoOtherWork();
DoOtherWork();
}
private Task<bool> StartAsync()
{
var taskCompletion = new TaskCompletionSource<bool>();
service.startFinished += (p, e) =>
{
taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false);
};
return taskCompletion.Task;
}
private void DoingWork()
{
for(int i = 0; i < 100; ++i)
{
}
service.StartFinished(project, error);
}
private void DoOtherWork()
{
for (int i = 0; i < 100000; ++i)
{
}
}
很明显,每当有人调用 DoingWork() 时,都会收到事件,大家都很高兴!如果有人有任何更好的建议请提供,因为我只是在学习如何正确使用 TPL。