2012-01-05 34 views
9

Tôi có một phương thức lấy đối số gọi lại để thực thi không đồng bộ, nhưng khối catch dường như không bắt bất kỳ ngoại lệ nào được gọi bằng lệnh đồng bộ (this.Submit đề cập đến một phương thức đồng bộ) .Bắt một ngoại lệ được ném vào một cuộc gọi lại không đồng bộ

public void Submit(FileInfo file, AnswerHandler callback) 
{ 
    SubmitFileDelegate submitDelegate = new SubmitFileDelegate(this.Submit); 
    submitDelegate.BeginInvoke(file, (IAsyncResult ar) => 
    { 
     string result = submitDelegate.EndInvoke(ar); 
     callback(result); 
    }, null); 
} 

Có cách nào để bắt ngoại lệ ném bởi thread mới và gửi nó đến các chủ đề ban đầu? Ngoài ra, đây có phải là cách "thích hợp" để xử lý ngoại lệ không đồng bộ không? Tôi đã viết mã của mình để nó có thể được gọi như thế này (giả sử vấn đề ngoại lệ là cố định):

try 
{ 
    target.Submit(file, (response) => 
    { 
     // do stuff 
    }); 
} 
catch (Exception ex) 
{ 
    // catch stuff 
} 

nhưng có cách nào thích hợp hơn hoặc thanh lịch để làm điều này?

+0

Khối catch trong mẫu mã đầu tiên của bạn sẽ bắt được một ngoại lệ được gọi bằng cách gọi lại hoặc bởi EndInvoke.Khối catch trong mẫu mã thứ hai của bạn sẽ bắt bất kỳ ngoại lệ nào được ném bởi hàm tạo SubmitFileDelegate hoặc bởi BeginInvoke. Mà một trong những không làm những gì bạn mong đợi/muốn nó để làm gì? – dgvid

+0

Rất tiếc, đã quên xóa điều đó. Tôi muốn người thứ hai làm việc đúng cách, nhưng hiện tại, không phải thế. – kevmo314

+0

Bạn có thể chỉ ra cách 'SubmitFileDelegate' được định nghĩa không? – GolfWolf

Trả lời

8

Đây không phải là một 'thực hành tốt nhất' giải pháp, nhưng tôi nghĩ đó là một cái đơn giản mà nên làm việc.

Thay vì có các đại biểu được định nghĩa là

private delegate string SubmitFileDelegate(FileInfo file); 

định nghĩa nó như

private delegate SubmitFileResult SubmitFileDelegate(FileInfo file); 

và xác định các SubmitFileResult như sau:

public class SubmitFileResult 
{ 
    public string Result; 
    public Exception Exception; 
} 

Sau đó, phương pháp mà thực hiện gửi tệp (không được hiển thị trong câu hỏi) nên được định nghĩa như sau:

private static SubmitFileResult Submit(FileInfo file) 
{ 
    try 
    { 
     var submissionResult = ComplexSubmitFileMethod(); 

     return new SubmitFileResult { Result = submissionResult }; 
    } 
    catch (Exception ex) 
    { 
     return new SubmitFileResult {Exception = ex, Result = "ERROR"}; 
    } 
} 

Bằng cách này, bạn sẽ kiểm tra đối tượng kết quả, xem liệu nó có tập kết quả hoặc trường ngoại lệ và hành động tương ứng.

+0

Cuộc gọi này có phải là đồng bộ không? Tôi đã thử đặt một thử/bắt trong lời gọi BeginInvoke (và sau đó mặc dù với ví dụ của bạn) nhưng nó không có vẻ để bắt ngoại lệ. – kevmo314

+0

Không, nó không đồng bộ. Xin lưu ý rằng có hai phương thức 'Gửi': là phương thức mà tôi đã mô tả ở trên (phải khớp với định nghĩa' SubmitFileDelegate') và câu lệnh bạn đã đưa ra trong câu hỏi, rằng 'BeginInvoke' (nghĩa là nó là một cuộc gọi không đồng bộ)). – GolfWolf

3

Tóm lại, không.

Khi bạn gọi submitDelegate.BeginInvoke, nó sẽ sinh ra chuỗi mới, trả về và thoát khỏi khối try/catch của bạn ngay lập tức (trong khi chuỗi mới chạy ẩn).

Bạn có thể, tuy nhiên, bắt tất cả hợp ngoại lệ unhandled như thế này:

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(YourException);

này sẽ bắt tất cả mọi thứ trong lĩnh vực thi công, tuy (không chỉ là phương pháp async của bạn).

+0

Có cách nào ưu tiên để xử lý ngoại lệ sau đó không? Tôi đã từng có callbacks giống như chức năng (err, result) {} từ thế giới JS, nhưng tôi đã không thấy bất cứ điều gì giống như vậy trong các mẫu mã C# mà tôi đã xem qua vì vậy tôi không chắc liệu đó có phải là đó là nghĩa vụ phải được thực hiện trong C# ...: S – kevmo314

+0

@ w0lf của câu trả lời là về cơ bản đó; bạn bọc ngoại lệ xảy ra trong loại phản hồi của bạn và kéo nó ra sau khi hoàn thành. –

9

Nếu bạn đang nhắm mục tiêu .NET 4.0, bạn có thể sử dụng Thư viện song song nhiệm vụ mới và quan sát thuộc tính Exception của đối tượng.

public Task Submit(FileInfo file) 
{ 
    return Task.Factory.StartNew(() => DoSomething(file)); 
} 

private void DoSomething(FileInfo file) 
{ 
    throw new Exception(); 
} 

Sau đó sử dụng nó như thế này:

Submit(myFileInfo).ContinueWith(task => 
{ 
    // Check task.Exception for any exceptions. 

    // Do stuff with task.Result 
}); 

nơi DoSomething là phương pháp mà bạn muốn gọi không đồng bộ, và các đại biểu để bạn vượt qua ContinueWith là callback của bạn.

Thông tin thêm về xử lý ngoại lệ trong TPL có thể được tìm thấy ở đây: http://msdn.microsoft.com/en-us/library/dd997415.aspx

Các vấn đề liên quan