새로운 .NET Core 3으로 전환하는 동안 IAsynsDisposable
다음과 같은 문제가 발생했습니다.
문제의 핵심 : DisposeAsync
예외가 발생하면이 예외는 await using
-block 내부에 발생한 예외를 숨 깁니다 .
class Program
{
static async Task Main()
{
try
{
await using (var d = new D())
{
throw new ArgumentException("I'm inside using");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message); // prints I'm inside dispose
}
}
}
class D : IAsyncDisposable
{
public async ValueTask DisposeAsync()
{
await Task.Delay(1);
throw new Exception("I'm inside dispose");
}
}
잡히면- AsyncDispose
예외가 발생하고 예외가 await using
발생 AsyncDispose
하지 않는 경우에만 내부에서 예외가 발생 합니다 .
그러나 await using
가능하면 블록 에서 예외를 가져오고 블록이 성공적으로 완료 된 DisposeAsync
경우에만 -exception을 사용 하는 것이 좋습니다 await using
.
이론적 근거 : 수업 D
에서 일부 네트워크 리소스를 사용하고 일부 알림을 원격으로 구독 한다고 가정합니다 . 내부 코드 await using
가 잘못하여 통신 채널에 장애가 생길 수 있습니다. 그 후 Dispose의 코드가 정상적으로 통신을 종료하려고 시도하면 (예 : 알림 수신 거부) 코드가 실패합니다. 그러나 첫 번째 예외는 문제에 대한 실제 정보를 제공하고 두 번째 예외는 단지 두 번째 문제입니다.
다른 경우에는 주요 부분이 통과되어 폐기가 실패한 경우 실제 문제는 내부 DisposeAsync
에 있으므로 예외 DisposeAsync
는 관련 문제입니다 . 즉, 내부의 모든 예외를 억제 DisposeAsync
하는 것은 좋은 생각이 아닙니다.
나는 비 비동기 경우와 같은 문제가 있음을 알고있는 예외 finally
재정의 예외 try
, 그것을 던져하지 않는 것이 좋습니다 그 이유는 Dispose()
. 그러나 네트워크 액세스 클래스를 사용하면 메소드 닫기에서 예외를 억제하는 것이 전혀 좋지 않습니다.
다음 도우미를 사용하여 문제를 해결할 수 있습니다.
static class AsyncTools
{
public static async Task UsingAsync<T>(this T disposable, Func<T, Task> task)
where T : IAsyncDisposable
{
bool trySucceeded = false;
try
{
await task(disposable);
trySucceeded = true;
}
finally
{
if (trySucceeded)
await disposable.DisposeAsync();
else // must suppress exceptions
try { await disposable.DisposeAsync(); } catch { }
}
}
}
그리고 그것을 사용하십시오
await new D().UsingAsync(d =>
{
throw new ArgumentException("I'm inside using");
});
그것은 추악한 것입니다 (그리고 using 블록 내부의 초기 반환과 같은 것을 허용하지 않습니다).
가능하면 좋은 정식 해결책이 await using
있습니까? 인터넷에서 검색해도이 문제에 대해 논의하지 못했습니다.
CloseAsync
수단이 있다는 것은 그것이 실행되도록 추가주의를 기울여야한다는 것을 의미합니다. 방금 using
-block 끝에 넣으면 조기 반환 등 (이것이 우리가하고 싶은 것입니다)과 예외 (이것이 우리가 일어나고 싶은 것입니다)에서 건너 뜁니다. 그러나 그 아이디어는 유망 해 보인다.
Dispose
"일이 잘못되었을 수도 있습니다. 상황을 개선하기 위해 최선을 다하지만 상황을 악화시키지 마십시오."라는 이유 AsyncDispose
는 무엇인지 알 수 없습니다.
DisposeAsync
정리하기 위해 최선을 다 하지만 던지지 않는 것이 옳은 일입니다. 당신은 의도적 인 조기 수익 에 대해 이야기하고있었습니다 . 의도적 인 조기 수익은 실수로 전화를 우회 할 수 있습니다 CloseAsync
.
Close
이러한 이유로 별도의 메소드 가 있다고 생각 합니다. 아마도 똑같이하는 것이 현명 할CloseAsync
것입니다.DisposeAsync
최선을 다하고 조용히 실패합니다.