Я прочитываю книгу о Библиотеке Параллели Задачи C# и имею следующий пример, но TaskScheduler. Обработчик UnobservedTaskException никогда не инициирован. Кто-либо может дать мне какой-либо ключ к разгадке относительно почему?
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
{
eventArgs.SetObserved();
((AggregateException)eventArgs.Exception).Handle(ex =>
{
Console.WriteLine("Exception type: {0}", ex.GetType());
return true;
});
};
Task task1 = new Task(() =>
{
throw new ArgumentNullException();
});
Task task2 = new Task(() => {
throw new ArgumentOutOfRangeException();
});
task1.Start();
task2.Start();
while (!task1.IsCompleted || !task2.IsCompleted)
{
Thread.Sleep( 5000 );
}
Console.WriteLine("done");
Console.ReadLine();
К сожалению, этот пример никогда не покажет вам ваш код. Исключение UnobservedTaskException
произойдет только в том случае, если задача будет собрана сборщиком мусора, при этом исключение не будет отслеживаться - пока вы сохраняете ссылку на задачу1
и задачу2
, сборщик мусора. никогда не будет собирать, и вы никогда не увидите свой обработчик исключений.
Чтобы увидеть поведение UnobservedTaskException
в действии, я бы попробовал следующее (надуманный пример):
public static void Main()
{
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
{
eventArgs.SetObserved();
((AggregateException)eventArgs.Exception).Handle(ex =>
{
Console.WriteLine("Exception type: {0}", ex.GetType());
return true;
});
};
Task.Factory.StartNew(() =>
{
throw new ArgumentNullException();
});
Task.Factory.StartNew(() =>
{
throw new ArgumentOutOfRangeException();
});
Thread.Sleep(100);
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
Console.ReadKey();
}
Это покажет вам ваши сообщения. Первый вызов Thread.Sleep (100)
предоставляет достаточно времени для выполнения задач. Сбор и ожидание заставляет сборщик мусора, который запускает ваш обработчик событий 2 раза.
Исключение не будет «незамеченным» в этом примере фрагмента. Только когда сборщик мусора избавится от экземпляров Task. Вам придется переписать его так:
class Program {
static void Main(string[] args) {
TaskScheduler.UnobservedTaskException += ( object sender, UnobservedTaskExceptionEventArgs eventArgs ) =>
{
eventArgs.SetObserved();
( (AggregateException)eventArgs.Exception ).Handle( ex =>
{
Console.WriteLine("Exception type: {0}", ex.GetType());
return true;
} );
};
Run();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("done");
Console.ReadLine();
}
static void Run() {
Task task1 = new Task(() => {
throw new ArgumentNullException();
});
Task task2 = new Task(() => {
throw new ArgumentOutOfRangeException();
});
task1.Start();
task2.Start();
while (!task1.IsCompleted || !task2.IsCompleted) {
Thread.Sleep(50);
}
}
}
Не делайте этого, используйте Task.Wait ().