2013-05-14 44 views
7

Tôi đang cố gắng để chạy các đoạn mã sau:Tại sao ngoại lệ này không bị bắt?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var task = Task.Factory.StartNew(() => 
      { 
       throw new ApplicationException("message"); 
      }); 
     try 
     { 
      task.ContinueWith(t => Console.WriteLine("End")); 
     } 
     catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 
    } 
} 

tôi mong đợi rằng Exception sẽ bị bắt ở vị trí sau:

 catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 

Nhưng điều này không xảy ra. Tại sao cái này rất?

+0

Câu trả lời được giải quyết những gì và cách thực hiện nhưng không phải là "lý do" (ngoại lệ không bị bắt). Tôi tin rằng lý do này là quan trọng để hiểu và nó được giải thích trong bài viết của Stephen Toub [Xử lý ngoại lệ trong .NET 4.5] (http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876. aspx) mà là một-phải đọc] –

Trả lời

9

Bạn chỉ cần in ra các task - đó sẽ không thậm chí đã hoàn thành.

In ra tác vụ không đợi quá trình hoàn thành hoặc cố gắng tìm nạp giá trị.

Nếu bạn thay đổi mã của bạn để:

try 
{ 
    task.Wait(); 
} 

... sau đó tôi mong đợi nó để bắt ngoại lệ.

(Tôi đã từng sử dụng Task<T>.Result, nhưng tôi nhận thấy đây là một nhiệm vụ không có giá trị trả về, vì vậy nó sẽ chỉ được các phi generic Task.)

+0

@NominSim No. Các đại biểu chính nó sẽ không có được chạy được nêu ra khi 'StartNew' trả về.Nó không thể ném một ngoại lệ trên dòng đó khi ngoại lệ vẫn chưa đạt được. – Servy

+1

@NominSim: Nó bị chặn bởi việc tìm nạp thuộc tính 'Result' bị chặn. –

+1

@NominSim 'ApplicationException' được đưa ra từ chuỗi khác. Trong chủ đề đó, đó là kêu gọi các đại biểu vô danh được cung cấp, nó cuối cùng sẽ bị bắt (trong một khối catch ở đâu đó trong nội bộ của mã 'Task'). Nó không được ném lại từ chuỗi chính khi tác vụ được tạo. Khi chủ đề chính sau đó chờ đợi nhiệm vụ, một khi nhiệm vụ hoàn thành, nó sẽ thông báo rằng nhiệm vụ đã kết thúc với một ngoại lệ cấp cao nhất; ngoại lệ đó sau đó được ném lại (trong một gói 'AggregateException') trong chuỗi chính bởi vì đó là cách thực hiện của phương thức' Wait' một cách rõ ràng. – Servy

-4

Nguyên nhân tuyên bố của bạn không có trong lần thử, nhưng trước khi nó ... catch sẽ bắt tất cả các ngoại lệ từ bên trong cố gắng dấu ngoặc nhọn ...

+3

Tôi nghĩ rằng bạn đã hiểu lầm bản chất của nhiệm vụ. –

+0

Điều này đơn giản là không đúng sự thật. Một ví dụ ngược lại dễ dàng: đặt nội dung của khối 'try' thành' task.Result' và nó sẽ thực sự kết thúc việc ném lại ngoại lệ được tạo ra trong ủy nhiệm xác định nhiệm vụ. – Servy

+0

@Jon Skeet> Nhìn thấy các downvotes, tôi nghĩ rằng tôi đã hiểu lầm toàn bộ câu hỏi thực sự :-) –

1

Cách Task công trình, mã mà kết thúc lên gọi đại biểu bạn vượt qua đến StartNew sẽ bị bắt, cuối cùng và Exception sẽ được lưu trữ trong trường mẫu của tác vụ. Ngoại lệ đó có thể được kiểm tra bằng cách xem tài sản task.Exception. Dòng Console.WriteLine(task) chỉ gọi số task.ToString trong nội bộ. Phương pháp đó sẽ không dẫn đến ngoại lệ bị ném hoặc bị ném lại.

Tuy nhiên, trong một số trường hợp ngoại lệ bị bắt sẽ được ném lại. Hai ví dụ là khi truy cập Result và gọi Wait, cũng như khi bạn await một tác vụ trong C# 5.0.

Các mã sau đây:

try 
{ 
    task.Wait(); 
} 
catch (AggregateException aex) 
{ 
    Console.Write(aex.InnerException.Message); 
} 

sẽ dẫn đến việc ngoại lệ lưu trữ được tái ném và thông điệp ngoại lệ sẽ được in.

+0

Ngoại trừ ngay cả với dấu chấm phẩy, bạn không thể sử dụng quyền truy cập thuộc tính làm tuyên bố. –

+0

@LuisFilipe Tôi đã chỉnh sửa sai lầm mà anh ta đang đề cập đến. Chỉ cần xem lịch sử sửa đổi. – Servy

+0

@LuisFilipe Thực ra, tôi đã sửa nó trong cửa sổ 5 phút, vì vậy nó sẽ không nằm trong lịch sử sửa đổi; nhưng tôi đã có một sai lầm mà tôi đã cố định. – Servy

-2

AggregateException and ApplicationException là cả hai con của cùng một lớp, System.Exception. AggregateException không phải là ApplicationException

+1

Điều này không liên quan. Không có ngoại lệ nào được ném từ khối 'try' của OP. – Servy

+0

Vâng, tôi sẽ đi ra ngoài một chi và nói rằng 'ném mới ApplicationException ("tin nhắn"); 'không phải là thực hiện thực tế của nhiệm vụ này. Nó có thể là một lỗi đánh máy trong việc tạo ra ví dụ và không liên quan gì đến vấn đề thực sự. –

+0

@NickFreeman Không. Điều đó không đúng chút nào. Lớp 'Task' sẽ bọc bất kỳ trường hợp ngoại lệ nào được ném ra từ bên trong cơ thể của nó trong một' AggregateException', do đó việc sử dụng ngoại lệ đó là thích hợp. Vấn đề, như tôi mô tả trong câu trả lời của tôi, là OP cần sử dụng 'task.Wait()'. Kết quả thay đổi nhỏ trong chương trình hoạt động chính xác như dự định. – Servy

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