6

Tôi có một phương thức Async trả về một nhiệm vụ.Mẫu để triển khai các phương thức đồng bộ hóa về nhiệm vụ không song song (Dịch/Unwrapping AggregateExceptions)

Tôi cũng muốn cung cấp một tương đương đồng bộ, nhưng tôi không muốn người tiêu dùng của nó phải đi giải nén AggregateException s.

Bây giờ tôi hiểu rằng toàn bộ ý tưởng là bạn không thể tự ý chọn một cách tổng quát, và tôi biết tôi có thể đọc thêm nhiều bài viết của Stephen Toub (tôi sẽ, nhưng không phải bây giờ) và tôi sẽ hiểu tất cả và có thể tự quyết định.

Tạm thời, tôi muốn sử dụng thực tế là nhiệm vụ của tôi thực sự chỉ là chuỗi công việc mà không có song song, chỉ cần can thiệp Waits (không, không phải TPL DataFlow) mà không nên dẫn đến nhiều hơn một ngoại lệ. Trong trường hợp đó, nó sẽ là thích hợp để xử lý như sau:

CallAsync().Wait(); 
} 
catch(AggregateException ae) 
{ 
    throw ae.Flatten().First() 

hay tôi đảm bảo rằng một AggregateException luôn có một InnerException ngay cả khi có nhiều hơn một. Hoặc là có trường hợp tôi nên quay trở lại .Flatten().First()?


Trong một số tài liệu TPL, tôi thấy một tham chiếu đến một phương pháp Unwrap() trên AggregateException (không chắc chắn nếu nó là một phần mở rộng hoặc một cái gì đó trong một phiên bản beta).

Là một giữ chỗ, tôi đang làm:

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     var translated = ex.InnerException ?? ex.Flatten().InnerExceptions.First(); 
     if (translated == null) 
      throw; 
     throw translated;     } 
} 

Task CallAsync(){ ... 

Trả lời

21

Không có "sạch" cách để làm điều này mà tôi biết. Bạn không thể sử dụng throw someInnerException; vì bạn sẽ mất chồng ở bất cứ nơi nào ngoại lệ bắt nguồn trong luồng công việc không đồng bộ và nếu bạn chỉ sử dụng throw;, bạn rõ ràng sẽ truyền bá số AggregateException. Những gì bạn sẽ phải làm cho các phương pháp đồng bộ là có một số loại "wrapper" ngoại lệ mà bạn có thể công cụ ngoại lệ đầu tiên của AggregateException vào và sau đó ném mà luôn từ phiên bản đồng bộ của phương pháp.

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     throw new MyConsistentWrapperException("An exception occurred while executing my workflow. Check the inner exception for more details.", ex.Flatten().InnerExceptions.First()); 
    } 
} 

FWIW, họ đã giải quyết này trong 4,5 với the new ExceptionDispatchInfo class mà sẽ giúp bạn sắp xếp hợp ngoại lệ trên chủ đề mà không chia nhau phần stack. Sau đó, bạn có thể viết phiên bản đồng bộ như sau:

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     ExceptionDispatchInfo.Capture(ex.Flatten().InnerExceptions.First()).Throw(); 
    } 
} 
+1

Cảm ơn; đặc biệt là cho các điểm mất stack mà tôi đã xem xét và sau đó chuyển sang một mắt mù (thậm chí không biết nếu bình thường PreserveStackTrace lừa sẽ làm việc như tôi là dưới sự tin tưởng trung bình vì vậy thậm chí không thể thử). Câu hỏi cuối cùng (và điểm bắt đầu thực sự của tôi) - bất kỳ ý tưởng nào tại sao hầu hết các mẫu sử dụng '.InnerException' thay cho' .Flatten(). InnerExceptions.First() 'hoặc một số cách khác để mở - ** là chúng tương đương hay không **? Nếu có, bất kỳ tài liệu tham khảo? Có cách nào khác để unwrapping - bất kỳ liên kết được đánh giá cao ... –

+0

Nếu bạn nhìn vào các nhà xây dựng AggregateException với ILDasm bạn sẽ thấy rằng cuối cùng có một nhà xây dựng tư nhân (string, IList ) được ủy nhiệm bởi các triển khai khác và trong hàm tạo đó, chúng gọi hàm tạo Ngoại lệ cơ sở, vượt qua ngoại lệ đầu tiên trong tham số ILO làm tham số innerException. Tuy nhiên, vì ngoại lệ đầu tiên COULD về mặt kỹ thuật là một AggregateException khác, sử dụng Flatten() là cách được bảo đảm để nhận được ngoại lệ không phải là AggregateException đầu tiên. –

+0

Tuyệt, điều đó giải thích nó một cách hoàn hảo. Tôi muốn một trong 50 trang tài liệu và bài viết có thể giải thích nó một cách thành công. (Tôi chưa có tại TPL w/một trình biên dịch ngược - vì lý do nào đó tôi xem xét nó về mặt tinh thần ngoài giới hạn.Đối với cách tôi giải thích không dùng thái độ đó để WCF ...: D) –

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