2013-12-10 5 views
0

비동기식 흐름 중에 프로그램 제어를 처리하는 방법을 이해하는 데 어려움을 겪고 있습니다.비동기 호출의 제어 흐름

나는 세션을 시작하는 것을 호출하는 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 또는 오류를 어떻게받을 수 있습니까?

답변

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 매개 변수에 따라 이 방법은 다소 바보 스럽지만 잘하면 사용자의 ServiceProvider.Startup 메소드의 동작과 유사합니다.

당신은 TaskCompletionSource 사용하여 작업에 비동기 시작을 변환 할 수 있습니다 : 생산 코드합니다 (Start 이벤트로부터 신호 오류가 Exception로 변환하는 방법을

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; 
} 

공지 사항을 대신 입력 한 사용자 지정 예외를 사용해야합니다).

비동기를 사용하여 매우 많은 동기 코드와 같은 실제로 비동기 비록 당신이 지금 보이는 코드를 작성할 수 있습니다 C 번호의 기능을 기다리고 있습니다 : 오류가 Start 이벤트에 의해보고

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); 
    } 
} 

경우 당신이 지금 할 수있는 catch 블록에서 처리하십시오. 또한 세션 ID는 단순히 함수의 반환 값입니다. "마법"은 Taskawait을 사용하면 작업 완료시 작업 결과를 반환하고 작업에 예외가 발생하면 작업을 기다리는 스레드에서 잡힐 수 있다는 것입니다.

2

TaskCompletionSource를 사용하여 이벤트를 기다릴 수 있습니다. 이 기능의 닷넷 4.5에서 사용할 수 :

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 
    } 
} 

참고 :

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; 
    } 
} 

호출은 같을 것이다.