2015-06-22 50 views
1

我不確定爲什麼這不起作用。我懷疑這是與獨立的工作線程有關。我一直無法找到任何有關以這種方式捕捉異常的工作。在匿名回調中捕獲異常

我想我可以創建一個任務對象然後運行,但我寧願保留這個架構,因爲其中包含的代碼是非常複雜的。

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

塞維是對的。因爲它已經使用另一個線程異步,或者任務可能不是必需的。但你可以使用這個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/catch的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); 
     }); 
    } 

如果不允許有從MethodOne一個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()); 
     }); 
    }