오류가 발생한 작업 (예외가 설정된 태스크)을 기다리는 경우,await
스토어드 예외를 재발행합니다. 격납 예외가AggregateException
그것은 첫 번째를 제물로 바칠 것이고 나머지는 버릴 것입니다.
우리는 어떻게 사용할 수 있습니까?await
동시에 원본을 던지십시오.AggregateException
실수로 오류 정보를 잃지 않도록하기 위해?
물론이를 위해 해킹 된 솔루션을 생각해 볼 수도 있습니다 (예 :await
, 다음 전화Task.Wait
). 정말 깨끗한 솔루션을 찾고 싶습니다.가장 좋은 방법은 무엇입니까?
나는 주문 습관을 사용하는 것을 생각했다. 그러나 붙박이의TaskAwaiter
완전히 재현 할 방법이 확실치 않은 많은 마법이 있습니다. TPL 유형의 내부 API를 호출합니다. 나는 또한하지 않는다.필요그 모든 것을 재현하는 것.
다음과 같이 연주하고 싶다면 다음과 같이 짧게 준비하십시오 :
static void Main()
{
Run().Wait();
}
static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
await Task.WhenAll(tasks);
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
두 가지 예외 중 하나만 throw됩니다.Run
.
스택 오버플로에 대한 다른 질문은이 특정 문제를 해결하지 못합니다. 중복을 제안 할 때주의하십시오.
나는 당신의 질문 제목에 함축 된 의미에 동의하지 않습니다.await
의 행동은 바람직하지 않습니다. 대다수 시나리오에서 의미가 있습니다. 안에WhenAll
상황, 얼마나 자주 당신을합니까정말알 필요가있다모든오류 세부 정보 중 하나와 반대되는 부분?
주요 어려움AggregateException
는 예외 처리입니다. 즉, 특정 유형을 포착 할 수있는 능력을 잃게됩니다.
즉, 확장 메소드를 사용하여 원하는 동작을 얻는 것은 쉽습니다.
public static async Task WithAggregateException(this Task source)
{
try
{
await source.ConfigureAwait(false);
}
catch
{
throw source.Exception;
}
}
UnobservedTaskException
, 응용 프로그램 처리기)try
/catch
블록. - Stephen ClearyUnobservedTaskException
여전히 키우고있다.관찰되지 않은 예외가 발생하면 (프로세스를 더 이상 크래시하지 않습니다.) 관찰 된, 삼켜지는 예외가있는 유일한 경우는WhenAll
, 그리고 여러 예외가있을 때만 발생합니다. 그 중 하나는아니삼켰다. 너 진짜해야 해.시험예외를 무시하는 방법await
. - Stephen ClearyAggregateException
적어도. 언제든지토론을위한 아이디어 게시. 옆으로 : 기술적으로,await
해당 항목을 푸십시오.AggregateException
하지만 괜찮은 정신 모델입니다. - Stephen Cleary
나는 늦었지만 당신이 원하는 것을하는이 깔끔한 작은 트릭을 발견했다. 대기중인 작업에 대해 전체 예외 집합을 사용할 수 있으므로이 작업의 대기 또는 .Result를 호출하면 집계 예외가 발생합니다.
static void Main(string[] args)
{
var task = Run();
task.Wait();
}
public static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
var compositeTask = Task.WhenAll(tasks);
try
{
await compositeTask.ContinueWith((antecedant) => { }, TaskContinuationOptions.ExecuteSynchronously);
compositeTask.Wait();
}
catch (AggregateException aex)
{
foreach (var ex in aex.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
더 말할 수는 있지만 패딩 만있을뿐입니다. 그걸 가지고 놀아, 그들이 말하는대로 작동합니다. 조심해야합니다.
너는 이것을 원할지도 모른다.
하나님 (Jon Skeet)이 예외 처리를 기다리고 있다고 설명합니다.
(개인적으로 나는 기다리는 것을 멀리 부끄러워하지만, 그건 내가 선호하는 것임)
댓글에 대한 응답으로 (댓글 응답이 너무 깁니다)
그런 다음 스레드를 모범 사례와 유사한 인수에 대한 출발점으로 사용하십시오. 여기에 소스가 있습니다.
예외를 전달하기 위해 코드를 구현하지 않으면 (예 : 기다리고있는 비동기 패턴이 아마도 랩핑됩니다 ... 이벤트를 발생시킬 때 이벤트 args 객체에 추가합니다.) 예외는 행복하게 삼킨다. 임의의 수의 스레드를 실행하고 실행하는 시나리오가 있으면 순서 나 스레드를 종료하는 시점을 제어 할 수 없습니다. 또한 하나의 오류가 다른 오류와 관련이 있으면이 패턴을 사용하지 않아야합니다. 그러므로 당신은 나머지 부분의 실행이 completly independent임을 강력히 암시합니다. IE강하게이러한 스레드에 대한 예외가 이미 예외로 처리되었음을 의미합니다. 발생한 스레드 (예외)에서 예외를 처리하는 것 이상의 작업을 수행하려면 참조로 전달되는 잠금 모음에 예외를 추가해야합니다. 예외는 예외로 간주하지 않고 조각으로 간주합니다 정보의 - 동시 가방을 사용하여 그것이 출현 한 컨텍스트를 식별하는 데 필요한 정보에서 예외를 래핑하십시오.
사용 사례를 모으지 마십시오.
await
. 두 번째 것은 유효한 대답을 포함하고 있습니다. 감사. 다른 답변을 며칠 동안이나 들여 보내 드리겠습니다.베스트해결책. - usr
나는 예상했던 예외만을 잡으려고 연습을 포기하고 싶지 않습니다. 이것은 다음 확장 메소드로 연결됩니다.
public static async Task NoSwallow<TException>(this Task task) where TException : Exception {
try {
await task;
} catch (TException) {
var unexpectedEx = task.Exception
.Flatten()
.InnerExceptions
.FirstOrDefault(ex => !(ex is TException));
if (unexpectedEx != null) {
throw new NotImplementedException(null, unexpectedEx);
} else {
throw task.Exception;
}
}
}
소비 코드는 다음과 같이 갈 수 있습니다.
try {
await Task.WhenAll(tasks).NoSwallow<MyException>();
catch (AggregateException ex) {
HandleExceptions(ex);
}
뼈대 예외는 동시 세계에서와 같은 효과를냅니다.MyException
우연히. 포장은NotIplementedException
원본 스택 추적을 풀지 않습니다.
await
그들이 그랬던 것처럼?blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876.aspx - Matthew Watson