비동기식 프로그래밍 오류 처리 ERROR HANDLING
7139 단어 error
Chapter 16 , "Errors and Exceptions,"provides detailed coverage of errors and exception handling. However, in the context of asynchronous methods, you should be aware of some special handling of errors.
Let's start with a simple method that throws an exception after a delay (code file ErrorHandling/Program.cs):
static async Task ThrowAfter(int ms, string message)
{
await Task.Delay(ms);
throw new Exception(message);
}
If you call the asynchronous method without awaiting it, you can put the asynchronous method within a try/catch block—and the exception will not be caught. That's because the method DontHandle has already completed before the exception from ThrowAfter is thrown. You need to await the ThrowAfter method, as shown in the following example:
private static void DontHandle()
{
try
{
ThrowAfter(200, "first");
// exception is not caught because this method is finished
// before the exception is thrown
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Warning
Asynchronous methods that return void cannot be awaited. The issue with this is that exceptions that are thrown from async void methods cannot be caught. That's why it is best to return a Task type from an asynchronous method. Handler methods or overridden base methods are exempted from this rule.
Handling Exceptions with Asynchronous Methods
A good way to deal with exceptions from asynchronous methods is to use await and put a try/catch statement around it, as shown in the following code snippet. The HandleOneError method releases the thread after calling the ThrowAfter method asynchronously, but it keeps the Task referenced to continue as soon as the task is completed. When that happens (which in this case is when the exception is thrown after two seconds), the catch matches and the code within the catch block is invoked:
private static async void HandleOneError()
{
try { await ThrowAfter(2000, "first"); } catch (Exception ex) { Console.WriteLine("handled {0}", ex.Message); }
}
Exceptions with Multiple Asynchronous Methods
What if two asynchronous methods are invoked that each throw exceptions? In the following example, first the ThrowAfter method is invoked, which throws an exception with the message first after two seconds. After this method is completed, the ThrowAfter method is invoked, throwing an exception after one second. Because the first call to ThrowAfter already throws an exception, the code within the try block does not continue to invoke the second method, instead landing within the catch block to deal with the first exception:
private static async void StartTwoTasks()
{
try
{
await ThrowAfter(2000, "first");
await ThrowAfter(1000, "second"); // the second call is not invoked
// because the first method throws
// an exception
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
Now let's start the two calls to ThrowAfter in parallel. The first method throws an exception after two seconds, the second one after one second. With Task.WhenAll you wait until both tasks are completed, whether an exception is thrown or not. Therefore, after a wait of about two seconds, Task.WhenAll is completed, and the exception is caught with the catch statement. However, you will only see the exception information from the first task that is passed to the WhenAll method. It's not the task that threw the exception first (which is the second task), but the first task in the list:
private async static void StartTwoTasksParallel()
{
try
{
Task t1 = ThrowAfter(2000, "first");
Task t2 = ThrowAfter(1000, "second");
await Task.WhenAll(t1, t2);
}
catch (Exception ex)
{
// just display the exception information of the first task
// that is awaited within WhenAll
Console.WriteLine("handled {0}", ex.Message);
}
}
One way to get the exception information from all tasks is to declare the task variables t1 and t2 outside of the try block, so they can be accessed from within the catch block. Here you can check the status of the task to determine whether they are in a faulted state with the IsFaulted property. In case of an exception, the IsFaulted property returns true. The exception information itself can be accessed by using Exception.InnerException of the Task class. Another, and usually better, way to retrieve exception information from all tasks is demonstrated next.
Using AggregateException Information
To get the exception information from all failing tasks, the result from Task.WhenAll can be written to a Task variable. This task is then awaited until all tasks are completed. Otherwise the exception would still be missed. As described in the last section, with the catch statement just the exception of the first task can be retrieved. However, now you have access to the Exception property of the outer task. The Exception property is of type AggregateException. This exception type defines the property InnerExceptions (not only InnerException), which contains a list of all the exceptions from the awaited for. Now you can easily iterate through all the exceptions:
private static async void ShowAggregatedException()
{
Task taskResult = null;
try
{
Task t1 = ThrowAfter(2000, "first");
Task t2 = ThrowAfter(1000, "second");
await (taskResult = Task.WhenAll(t1, t2));
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
foreach (var ex1 in taskResult.Exception.InnerExceptions)
{
Console.WriteLine("inner exception {0}", ex1.Message);
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Qiita의 API를 부를 때 끝에 슬래시를 붙이면 http://~로 리디렉션되므로 조심합시다.제목대로. curl 결과는 . 예전에 보았던 오류에 근거한 박자를 만났습니다 이것은 메시지처럼 HTTP 통신을 시도할 때 iOS가 차단하는 사람입니다. URLSession 에 건네주고 있는 url는 확실히 https...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.