Pengecualian Tugas tidak diamati baik dengan Menunggu Tugas atau mengakses properti Pengecualiannya. Akibatnya, pengecualian yang tidak teramati itu

100

Apa artinya ini dan bagaimana mengatasinya?

Saya menggunakan tugas TPL.

Seluruh kesalahan

Pengecualian Tugas tidak diamati baik dengan Menunggu Tugas atau mengakses properti Pengecualiannya. Akibatnya, pengecualian yang tidak teramati ditampilkan kembali oleh utas finalizer.

di System.Threading.Tasks.TaskExceptionHolder.Finalize ()

mscorlib.dll

MonsterMMORPG
sumber

Jawaban:

158

Jika Anda membuat Tugas, dan Anda tidak pernah memanggil task.Wait()atau mencoba mengambil hasil dari Task<T>, saat tugas dikumpulkan oleh pengumpul sampah, itu akan menghancurkan aplikasi Anda selama finalisasi. Untuk detailnya, lihat halaman MSDN tentang Penanganan Pengecualian di TPL .

Opsi terbaik di sini adalah "menangani" pengecualian. Ini dapat dilakukan melalui kelanjutan - Anda dapat melampirkan kelanjutan ke tugas, dan mencatat / menelan / dll pengecualian yang terjadi. Ini menyediakan cara yang bersih untuk mencatat pengecualian tugas, dan dapat ditulis sebagai metode ekstensi sederhana, yaitu:

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

Dengan cara di atas, Anda dapat mencegah tugas apa pun dari merobohkan aplikasi, dan mencatatnya, melalui:

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

Alternatifnya, Anda bisa berlangganan ke TaskScheduler.UnobservedTaskException dan menanganinya di sana.

Reed Copsey
sumber
17
Untuk hiburan tambahan, miliki metode rintisan statis Offdi kelas yang dinamai sebagai kata empat huruf pilihan Anda, dan gunakan ini untuk kelanjutan penampung semua. Membantu memerangi beberapa frustrasi yang terpendam dari pengecualian khusus ini.
Aaronaught
1
@ MonsterMMORPG Ya - Anda pada dasarnya harus menangkap atau menangani pengecualian di suatu tempat . Selama Anda menanganinya di suatu tempat, masalah inti Anda akan hilang.
Reed Copsey
1
Apakah tidak mungkin bahwa tugas dapat memunculkan pengecualian sebelum panggilan ke ContinueWith dibuat?
Tim Sylvester
1
@TimSylvester Kerangka akan tetap memetakannya melalui kelanjutan, meskipun itu terjadi "sebelum" kelanjutan dipasang
Reed Copsey
32
Catatan penting: Ini hanya diperlukan untuk .Net 4.0. Penanganan pengecualian diubah secara default .net 4.5untuk tidak merusak aplikasi . Lihat selengkapnya di Penanganan Pengecualian Tugas di .NET 4.5
i3arnon
43

Tentu; itu berarti Taskdiselesaikan setelah diserahkan ke pengumpulan sampah, tetapi tugas itu sendiri gagal. Ada dua perbaikan:

  • menangani tugas-tugas gagal langsung (gunakan ContinueWith(...)untuk berlangganan, dan periksa .IsFaulteddan .Exceptiondi Taskdalam parameter)
  • menangani TaskScheduler.UnobservedTaskExceptionacara tersebut, dan menandainya sebagai observasi (panggil e.SetObserved()setelah mencatat kesalahan)
Marc Gravell
sumber
4
+1 - Dengan satu tambahan - jika kelanjutan Anda tidak melakukan apa-apa selain memeriksa IsFaulted, Anda dapat menggunakan OnlyOnFaultedopsi kelanjutan dan menghindari pemeriksaan manual ...
Reed Copsey
sebenarnya ini terjadi di mana saya memanggil fungsi statis publik di dalam tugas tpl. menggunakan coba tangkap akan menyelesaikan masalah ini? apakah saya benar-benar perlu membuat tugas lain dan menunggu? terima kasih
MonsterMMORPG
4
1 untuk menyebutkan bahwa SetObservedpada UnobservedTaskExceptionEventArgskebutuhan untuk dipanggil.
James Webster
-17

Coba yang ini:

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;
}
h4165f8ghd4f854d6f8h
sumber
5
Ini salah satunya ??? Maksud kamu apa? Bisakah Anda menjelaskan apa kontribusi jawaban Anda terhadap jawaban sejauh ini?
Gert Arnold
Anda baru saja membuat tugas baru dengan melanjutkan yang kemudian akan gagal dan masuk ke situasi yang sama.
Robert Taylor
Solusi ini tampaknya sedikit berbelit-belit. Saya pikir Anda akan menyembunyikan fungsionalitas secara tidak sengaja tanpa keuntungan apapun.
Velocitas