(Các) ngoại lệ của Tác vụ không được quan sát bằng cách Chờ trên Tác vụ hoặc truy cập thuộc tính Ngoại lệ của nó. Kết quả là, ngoại lệ không được quan sát là


100

Điều này có nghĩa là gì và làm thế nào để giải quyết nó?

Tôi đang sử dụng các tác vụ TPL.

Toàn bộ lỗi

(Các) ngoại lệ của Tác vụ không được quan sát bằng cách Chờ trên Tác vụ hoặc truy cập thuộc tính Ngoại lệ của nó. Kết quả là, ngoại lệ không được quan sát đã được phát triển lại bởi chuỗi trình hoàn thiện.

tại System.Threading.Tasks.TaskExceptionHolder.Finalize ()

mscorlib

Câu trả lời:


158

Nếu bạn tạo một Nhiệm vụ và bạn không bao giờ gọi task.Wait()hoặc cố gắng truy xuất kết quả của a Task<T>, khi tác vụ được thu thập bởi bộ thu gom rác, nó sẽ hủy ứng dụng của bạn trong quá trình hoàn thiện. Để biết chi tiết, hãy xem trang của MSDN về Xử lý Ngoại lệ trong TPL .

Lựa chọn tốt nhất ở đây là "xử lý" ngoại lệ. Điều này có thể được thực hiện thông qua một phần tiếp theo - bạn có thể đính kèm phần tiếp theo cho nhiệm vụ và ghi nhật ký / nuốt / vv ngoại lệ xảy ra. Điều này cung cấp một cách rõ ràng để ghi nhật ký các trường hợp ngoại lệ của nhiệm vụ và có thể được viết dưới dạng một phương thức mở rộng đơn giản, tức là:

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var exception in aggException.InnerExceptions)
             LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

Với những điều trên, bạn có thể ngăn bất kỳ tác vụ nào phá vỡ ứng dụng và ghi lại nó, thông qua:

Task.Factory.StartNew( () => 
   { 
       // Do your work...
   }).LogExceptions();

Ngoài ra, bạn có thể đăng ký TaskScheduler.UnobservedTaskException và xử lý nó ở đó.


17
Để giải trí thêm, hãy có một phương thức gốc tĩnh Offtrong một lớp có tên là từ gồm bốn chữ cái mà bạn chọn và sử dụng phương thức này cho các liên tục về tổng hợp của bạn. Giúp chống lại một số sự thất vọng bị dồn nén từ ngoại lệ cụ thể này.
Aaronaught

1
@MonsterMMORPG Có - Về cơ bản, bạn phải bắt hoặc xử lý ngoại lệ ở đâu đó . Miễn là bạn xử lý nó ở đâu đó, vấn đề cốt lõi của bạn sẽ biến mất.
Reed Copsey

1
Không lẽ tác vụ có thể ném ra một ngoại lệ trước khi lệnh gọi ContinueWith được thực hiện?
Tim Sylvester

1
@TimSylvester Khung sẽ vẫn ánh xạ nó thông qua phần tiếp tục, ngay cả khi nó xảy ra "trước khi" phần tiếp theo được đính kèm
Reed Copsey

32
Lưu ý quan trọng: Điều này chỉ cần thiết cho .Net 4.0. Việc xử lý ngoại lệ đã được thay đổi theo mặc định .net 4.5để không chia nhỏ ứng dụng . Xem thêm trong công tác Xử lý ngoại lệ trong .NET 4.5
i3arnon

43

Chắc chắn rồi; nó có nghĩa là một Taskđã được hoàn thành sau khi được để lại cho bộ sưu tập rác, nhưng bản thân tác vụ đã thất bại. Có hai bản sửa lỗi:

  • xử lý trực tiếp các tác vụ không thành công (sử dụng ContinueWith(...)để đăng ký và kiểm tra .IsFaulted.Exceptiontrên Tasktham số)
  • xử lý TaskScheduler.UnobservedTaskExceptionsự kiện và đánh dấu sự kiện được quan sát (gọi e.SetObserved()sau khi ghi lỗi)

4
1 - Với một cú Ngoài ra - nếu tiếp tục của bạn đang làm gì, nhưng việc kiểm tra IsFaulted, bạn có thể sử dụng OnlyOnFaultedtùy chọn tiếp tục và tránh việc kiểm tra thủ công ...
Reed Copsey

thực sự điều này đã xảy ra khi tôi gọi một hàm tĩnh công khai bên trong một tác vụ tpl. sử dụng thử bắt sẽ giải quyết vấn đề này? tôi có thực sự cần tạo một nhiệm vụ khác và đợi nó không? cảm ơn
MonsterMMORPG

4
1 đề cập đến mà SetObservedtrên UnobservedTaskExceptionEventArgsnhu cầu để được gọi.
James Webster

-17

Hãy thử cái này:

public static void ThrowFirstExceptionIfHappens(this Task task)
{
    task.ContinueWith(t =>
    {
        var aggException = t.Exception.Flatten();
        foreach (var exception in aggException.InnerExceptions)
        {
            throw exception; // throw only first, search for solution
        }
    },
    TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}

public static Task CreateHandledTask(Action action) 
{
    Task tsk = Task.Factory.StartNew(action);
    tsk.ThrowFirstExceptionIfHappens();
    return tsk;
}

5
Của nó à ??? Ý anh là gì? Bạn có thể giải thích câu trả lời của bạn đóng góp gì cho câu trả lời cho đến nay không?
Gert Arnold

bạn vừa tạo một nhiệm vụ mới bằng cách tiếp tục, sau đó sẽ thất bại và rơi vào tình huống tương tự.
Robert Taylor

Giải pháp này có vẻ hơi phức tạp. Tôi nghĩ rằng bạn sẽ vô tình ẩn chức năng mà không có bất kỳ lợi ích nào.
Velocitas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.