ไม่พบข้อยกเว้นของงานโดยการรอบนงานหรือการเข้าถึงคุณสมบัติข้อยกเว้น เป็นผลให้ข้อยกเว้นที่ไม่สามารถสังเกตได้คือ


100

สิ่งนี้หมายความว่าอย่างไรและจะแก้ไขได้อย่างไร?

ฉันใช้งาน TPL

ข้อผิดพลาดทั้งหมด

ไม่พบข้อยกเว้นของงานโดยการรอบนงานหรือการเข้าถึงคุณสมบัติข้อยกเว้น ด้วยเหตุนี้ข้อยกเว้นที่ไม่สามารถสังเกตได้จึงถูกเปลี่ยนใหม่โดยเธรด Finalizer

ใน System.Threading.Tasks.TaskExceptionHolder.Finalize ()

mscorlib

คำตอบ:


158

หากคุณสร้างงานและคุณไม่เคยเรียกtask.Wait()หรือพยายามดึงผลลัพธ์ของ a Task<T>เมื่องานถูกรวบรวมโดยผู้รวบรวมขยะงานนั้นจะฉีกใบสมัครของคุณในระหว่างการสรุป สำหรับรายละเอียดโปรดดูหน้า MSDN ในการจัดการข้อยกเว้นใน TPL

ตัวเลือกที่ดีที่สุดคือ "จัดการ" ข้อยกเว้น สิ่งนี้สามารถทำได้ผ่านการสานต่อ - คุณสามารถแนบความต่อเนื่องกับงานและบันทึก / กลืน / ฯลฯ ข้อยกเว้นที่เกิดขึ้น นี่เป็นวิธีที่สะอาดในการบันทึกข้อยกเว้นของงานและสามารถเขียนเป็นวิธีการขยายแบบธรรมดาได้เช่น:

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);
}

ด้วยวิธีการข้างต้นคุณสามารถป้องกันไม่ให้งานใด ๆ ฉีกแอพและบันทึกผ่าน:

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

หรือคุณสามารถสมัครรับTaskScheduler.UnobservedTaskExceptionและจัดการได้ที่นั่น


17
เพื่อความบันเทิงที่เพิ่มขึ้นให้ใช้วิธี Stub แบบคงที่Offในคลาสที่มีชื่อว่าเป็นคำสี่ตัวอักษรที่คุณเลือกและใช้สิ่งนี้สำหรับการจับต่อเนื่องทั้งหมดของคุณ ช่วยต่อสู้กับความขุ่นมัวที่ถูกกักขังจากข้อยกเว้นนี้
Aaronaught

1
@MonsterMMORPG ใช่ - คุณโดยทั่วไปมีการจับหรือจัดการข้อยกเว้นบางแห่ง ตราบใดที่คุณจัดการกับมันที่ไหนสักแห่งปัญหาหลักของคุณจะหมดไป
Reed Copsey

1
เป็นไปไม่ได้ที่งานจะเกิดข้อยกเว้นก่อนที่จะมีการเรียกใช้ ContinueWith?
Tim Sylvester

1
@TimSylvester เฟรมเวิร์กจะยังคงแมปผ่านความต่อเนื่องแม้ว่ามันจะเกิดขึ้น "ก่อน" ก็ตามความต่อเนื่องจะถูกแนบมา
Reed Copsey

32
หมายเหตุสำคัญ: .Net 4.0นี้เป็นเพียงสิ่งที่จำเป็นสำหรับ การจัดการข้อยกเว้นก็เปลี่ยนโดยเริ่มต้นใน.net 4.5การไม่ฉีกลงแอพลิเคชัน ดูเพิ่มเติมในTask Exception Handling ใน. NET 4.5
i3arnon

43

แน่นอน; นั่นหมายถึงการTaskสรุปผลหลังจากถูกทิ้งให้ไปเก็บขยะ แต่งานนั้นล้มเหลว มีสองวิธีแก้ไข:

  • จัดการงานล้มเหลวโดยตรง (ใช้ContinueWith(...)สมัครและตรวจสอบ.IsFaultedและ.ExceptionบนTaskในพารามิเตอร์)
  • จัดการTaskScheduler.UnobservedTaskExceptionเหตุการณ์และทำเครื่องหมายที่สังเกต (โทรe.SetObserved()หลังจากบันทึกข้อผิดพลาด)

4
+1 - ด้วยการเพิ่มเพียงครั้งเดียว - หากความต่อเนื่องของคุณไม่ทำอะไรเลยนอกจากการตรวจสอบIsFaultedคุณสามารถใช้OnlyOnFaultedตัวเลือกการต่อเนื่องและหลีกเลี่ยงการตรวจสอบด้วยตนเอง ...
Reed Copsey

จริงๆแล้วสิ่งนี้เกิดขึ้นที่ฉันเรียกว่าฟังก์ชันคงที่สาธารณะภายในงาน tpl การใช้ try catch จะช่วยแก้ปัญหานี้ได้หรือไม่ ฉันจำเป็นต้องสร้างงานอื่นและรอหรือไม่ ขอบคุณ
MonsterMMORPG

4
+1 สำหรับการกล่าวขวัญว่าSetObservedในUnobservedTaskExceptionEventArgsความต้องการที่จะเรียกว่า
James Webster

-17

ลองอันนี้:

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
อันนี้ ??? คุณหมายถึงอะไร? คุณช่วยอธิบายได้ไหมว่าคำตอบของคุณมีส่วนช่วยในคำตอบจนถึงตอนนี้อย่างไร
Gert Arnold

คุณเพิ่งสร้างงานใหม่โดยดำเนินการต่อซึ่งจะล้มเหลวและเข้าสู่สถานการณ์เดียวกัน
Robert Taylor

วิธีนี้ดูเหมือนจะซับซ้อนเล็กน้อย ฉันคิดว่าคุณจะซ่อนฟังก์ชันโดยไม่ได้ตั้งใจโดยไม่ได้รับประโยชน์ใด ๆ
Velocitas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.