2013-12-10 45 views
0

我很難理解如何在異步流程中處理程序控制。異步調用中的控制流程

我有一個SessionManager類,它調用發起會話,我們需要註冊 事件OnStartApplicationSessionResponse和我的控制權將返回到調用點。我會在某個時間後在事件處理程序中獲取會話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或錯誤,因爲我的控件現在處於調用位置?

回答

1

使用C#功能異步並等待您可以將異步流重寫爲類似於同步流的東西。你只提供你的代碼的一些片段,提供我創造了一些代碼,類似於你的代碼一個完整的例子:

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參數。該方法相當愚蠢,但有希望類似於您的方法的行爲。

您可以使用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 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只是該函數的返回值。 「魔術」是在Task上使用await將在任務完成時返回任務的結果,並且如果任務中引發異常,則可以在等待任務的線程上捕獲該異常。

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可用。