我在理解异步流程中如何处理程序控制方面遇到了困难。
我有一个SessionManager
类,它会调试会话,我们需要注册
对于事件OnStartApplicationSessionResponse
,我的控件将返回到调用点。我会在一段时间后在eventhandler中获取会话ID,如果出现错误,则会收到错误代码。
class SessionManager
{
public bool startUp(Object params)
{
try
{
serviceProvider = new ServiceProvider();
serviceProvider.OnStartApplicationSessionResponse += new StartApplicationSessionResponseHandler(ServiceProvider_OnStartApplicationSessionResponse);
serviceProvider.startUp(params);
}
}
public void ServiceProvider_OnStartApplicationSessionResponse(object sender, ServiceProvider.StartApplicationSessionResponseArgs e)
{
//e.getError
//I will get the session Id here or error code
}
}
当我的控件现在处于呼叫位置时,如何获取sessionId或错误?
答案 0 :(得分:2)
您可以使用TaskCompletionSource使事件等待。
class SessionManager
{
private ServiceProvider _serviceProvider;
public int SessionId
{
get;
private set;
}
public Task<bool> StartUp(Object param)
{
_serviceProvider = new ServiceProvider();
var tcs = new TaskCompletionSource<bool>();
_serviceProvider.OnStartApplicationSessionResponse += (sender, args) =>
{
// do your stuff
// e.g.
SessionId = 0xB00B5;
tcs.SetResult(true);
};
_serviceProvider.startUp(param);
return tcs.Task;
}
}
电话会是:
private static async void SomeButtonClick()
{
var mgr = new SessionManager();
var success = await mgr.StartUp("string");
if (success)
{
Console.WriteLine(mgr.SessionId);
// update ui or whatever
}
}
注意:此功能在.Net 4.5中可用。
答案 1 :(得分:1)
使用C#功能async并等待您可以将异步流重写为类似于同步流的内容。您只提供了代码的一些片段,以便提供一个完整的示例,我创建了一些类似于您的代码的代码:
class StartEventArgs : EventArgs {
public StartEventArgs(Int32 sessionId, Int32 errorCode) {
SessionId = sessionId;
ErrorCode = errorCode;
}
public Int32 SessionId { get; private set; }
public Int32 ErrorCode { get; private set; }
}
delegate void StartEventHandler(Object sender, StartEventArgs e);
class ServiceProvider {
public event StartEventHandler Start;
public void Startup(Boolean succeed) {
Thread.Sleep(TimeSpan.FromSeconds(1));
if (succeed)
OnStart(new StartEventArgs(321, 0));
else
OnStart(new StartEventArgs(0, 123));
}
protected void OnStart(StartEventArgs e) {
var handler = Start;
if (handler != null)
handler(this, e);
}
}
ServiceProvider.Startup
方法会在触发成功或失败的事件之前延迟一秒,具体取决于所提供的succeed
参数。该方法相当愚蠢,但希望与您的ServiceProvider.Startup
方法的行为类似。
您可以使用TaskCompletionSource
:
Task<Int32> PerformStartup(ServiceProvider serviceProvider, Boolean succeed) {
var taskCompletionSource = new TaskCompletionSource<Int32>();
serviceProvider.Start += (sender, e) => {
if (e.ErrorCode > 0)
throw new Exception(e.ErrorCode.ToString());
taskCompletionSource.SetResult(e.SessionId);
};
serviceProvider.Startup(succeed);
return taskCompletionSource.Task;
}
注意Start
事件发出的错误如何转换为Exception
(在生产代码中,您应该使用自定义异常类型)。
使用C#的async和await功能,你现在可以编写看起来非常像同步代码的代码,即使它实际上是异步的:
async void Startup(Boolean succeed) {
var serviceProvider = new ServiceProvider();
try {
var sessionId = await PerformStartup(serviceProvider, succeed);
Console.WriteLine(sessionId);
}
catch (Exception ex) {
Console.WriteLine(ex);
}
}
如果Start
事件报告错误,您现在可以在catch
块中处理。会话ID也只是函数的返回值。 “神奇”是在await
上使用Task
将在任务完成时返回任务的结果,如果在任务中抛出异常,则可以在等待任务的线程上捕获该任务。 / p>