2015-06-22 3 views
1

Я не уверен, почему это не работает. У меня есть подозрение, что это связано с отдельными рабочими потоками. Таким образом, я не смог найти какую-либо работу по захвату исключений.Ловля исключений при анонимном обратном вызове

Я думаю, что я могу создать объект Task, а затем запустить его, но я бы предпочел сохранить эту архитектуру, потому что код, содержащийся в ней, очень сложный.

public void MethodOne(){   
    try{ 
    MethodTwo(response =>{ 
     //Do something with the response 
    }); 
    } 
    catch(Exception error){ 
    //This never executes when method two throws exception 
    } 
} 


public void MethodTwo(Action<Object> callback){ 
    //Conduct async call to external server 
    AppServer.MakeCall(response =>{  
     if(response.IsValid) 
     callback(response.Object); 
     else 
     throw new FooException(); 
    }); 
} 

ответ

1

Поскольку эта программа является асинхронным, обратный вызов даже не вызывается до тех пор после MethodTwo не вернулся, и что нить пошел на покинуть try блок и сделать больше и лучше вещи. Обратный вызов вызывается другим потоком в какой-то момент в возможно отдаленном будущем.

Как вы уже упоминали, один из возможных - использовать Task, а не использовать обратные вызовы. Одним из основных преимуществ TPL является то, как он приближается к обработке ошибок. Если асинхронный метод возвращает Task, вы можете не только добавить обратный вызов, используя ContinueWith (или await), но также можете обрабатывать ошибки в этих продолжениях.

Способ обращения с использованием обратных вызовов состоит в том, чтобы принимать два обратных вызова, один для вызова, когда ответ действителен, а второй - при возникновении исключения/ошибки. Для звонящего это не так хорошо, как использование try/catch, но это лучшее, что вы можете сделать в модели с обратным вызовом.

+0

Для процветания я решил пройти два обратных вызова. Один для успеха и один для неудачи. Я сделал их анонимными, так что это получилось довольно аккуратно. –

0

Servy is right. Поскольку он уже асинхронен с использованием другого потока или задачи, возможно, не обязательно. Но для этого вы можете использовать TaskCompletionSource.

public void MethodOne() 
    { 
     MethodTwo() 
      .ContinueWith(task => 
      { 
       if (task.IsFaulted) 
        // Handle error in task.Exception 
        ; 
       else 
       { 
        object obj = task.Result; 
        // Handle object 
       } 
      }); 
    } 


    public Task<object> MethodTwo() 
    { 
     TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); 

     //Conduct async call to external server 
     AppServer.MakeCall(response => 
     { 
      if (Response.IsValid) 
       tcs.TrySetResult(response.Object); 
      else 
       tcs.TrySetException(new FooException()); 
     }); 

     return tcs.Task; 
    } 

Вы можете также сделать TRY/поймать внутри MethodTwo лямбда-аргумента и/или использовать полный объект Response вместо ответных данных объекта экземпляра only.`

public void MethodOne() 
    { 
     MethodTwo(response => 
      { 
       if (Response.IsValid) 
        callback(Response.Object); 
       else 
        throw new FooException(); // Or error handling directly 
      }); 
    } 


    public void MethodTwo(Action<Response> callback) 
    { 
     //Conduct async call to external server 
     AppServer.MakeCall(response => 
     { 
      callback(response); 
     }); 
    } 

Если вы не можете иметь ссылку на объект ответа от метадон, и/или не разрешено изменять обратный вызов подпись, то вы могли бы назвать действие обратного вызова, используя в качестве аргумента FooException callback(new FooException);

public void MethodOne() 
    { 
     MethodTwo(response => 
      { 
       if (response is FooException) 
       { 
        FooException exc = response as FooException; 
       } 
       else 
       { 
        // Handle response; 
       } 
      }); 
    } 

    public void MethodTwo(Action<object> callback) 
    { 
     //Conduct async call to external server 
     AppServer.MakeCall(response => 
     { 
      if (Response.IsValid) 
       callback(Response.Object); 
      else 
       callback(new FooException()); 
     }); 
    } 
Смежные вопросы