C#에서 예외를 다시 적용하는 올바른 방법은 무엇입니까?
이 작업을 수행하는 것이 더 나을까요?
try
{
...
}
catch (Exception ex)
{
...
throw;
}
또는 다음과 같습니다.
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
그들은 같은 일을 합니까?하나가 다른 하나보다 나은가요?
예외를 다시 적용하려면 항상 다음 구문을 사용해야 합니다.그렇지 않으면 스택 추적을 중지합니다.
throw;
결과로 생성된 추적을 인쇄하는 경우throw ex
당신은 그것이 예외의 실제 출처가 아닌 그 진술에서 끝난다는 것을 알게 될 것입니다.
기본적으로 사용하는 것은 형사 범죄로 간주되어야 합니다.throw ex
.
다른 곳에서 발생한 예외를 다시 적용해야 하는 경우(집계)예외, 대상호출예외) 또는 다른 스레드도 직접 다시 던져서는 안 됩니다.대신 필요한 모든 정보를 보존하는 ExceptionDispatchInfo가 있습니다.
try
{
methodInfo.Invoke(...);
}
catch (System.Reflection.TargetInvocationException e)
{
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e.InnerException).Throw();
throw; // just to inform the compiler that the flow never leaves the block
}
내가 선호하는 것은 사용하는 것입니다.
try
{
}
catch (Exception ex)
{
...
throw new Exception ("Add more context here", ex)
}
이렇게 하면 원래 오류는 보존되지만 개체 ID, 연결 문자열 등의 컨텍스트를 추가할 수 있습니다.종종 예외 보고 도구에는 보고할 5개의 연결된 예외가 있으며, 각 예외는 더 자세히 보고합니다.
변수(첫 번째 예제) 없이 예외를 던지면 스택 추적에 예외를 던졌던 원래 메서드가 포함됩니다.
두 번째 예에서는 스택 추적이 현재 방법을 반영하도록 변경됩니다.
예:
static string ReadAFile(string fileName) {
string result = string.Empty;
try {
result = File.ReadAllLines(fileName);
} catch(Exception ex) {
throw; // This will show ReadAllLines in the stack trace
throw ex; // This will show ReadAFile in the stack trace
}
첫 번째 스택은 예외의 원래 스택 추적을 보존하고, 두 번째 스택 추적을 현재 위치로 바꿉니다.
그러므로 첫 번째가 훨씬 더 좋습니다.
것을 에 동의합니다.throw
무엇이 잘못되었는지에 대한 정보를 가능한 한 많이 보존하거나, 문제를 일으킨 내부 사건에 대해 알고 싶어하는 가능성에 따라 내부 오류로 포함되거나 포함되지 않을 수 있는 새로운 예외를 던지고자 합니다.
하지만 예외가 있습니다.메서드가 다른 메서드를 호출하는 경우가 몇 가지 있으며 내부 호출에서 예외를 발생시키는 조건은 외부 호출에서 동일한 예외로 간주되어야 합니다.
하나의 예는 다른 컬렉션을 사용하여 구현된 특수 컬렉션입니다.예를 들면,DistinctList<T>
그것으로 끝List<T>
중복 항목은 거부합니다.
만약 누군가가 전화를 했다면ICollection<T>.CopyTo
당신의 수집 수업에서, 그것은 단지 직통 전화일 수도 있습니다.CopyTo
내부 컬렉션(예: 모든 사용자 지정 로직이 컬렉션에 추가하거나 설정하는 경우에만 적용됨). 그 은 이제해호전는조문일다컬전의 당신의 과 정확히 .ICollection<T>.CopyTo
.
이제, 여러분은 예외를 전혀 잡을 수 없었고, 그것이 통과되도록 내버려둘 수 없었습니다.는 그나여사예받습외다니에서 예외를 .List<T>
그들이 무언가를 부를 때DistinctList<T>
이것이 세상의 종말은 아니지만, 이러한 구현 세부 정보를 숨기는 것이 좋습니다.
또는 직접 확인할 수 있습니다.
public CopyTo(T[] array, int arrayIndex)
{
if(array == null)
throw new ArgumentNullException("array");
if(arrayIndex < 0)
throw new ArgumentOutOfRangeException("arrayIndex", "Array Index must be zero or greater.");
if(Count > array.Length + arrayIndex)
throw new ArgumentException("Not enough room in array to copy elements starting at index given.");
_innerList.CopyTo(array, arrayIndex);
}
에 더 . 그것을 할 수 것입니다. 그리고 우리는 아마도 그것을 다른 구현체에서 복사할 수 있습니다.CopyTo
단순한 패스스루가 아니라 우리가 직접 구현해야 했던 곳입니다.여전히, 그것은 불필요하게 앞으로 수행될 똑같은 검사를 반복하고 있습니다._innerList.CopyTo(array, arrayIndex)
그래서 그것이 우리 코드에 추가한 것은 버그가 있을 수 있는 6줄뿐입니다.
우리는 확인하고 포장할 수 있었습니다.
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentNullException ane)
{
throw new ArgumentNullException("array", ane);
}
catch(ArgumentOutOfRangeException aore)
{
throw new ArgumentOutOfRangeException("Array Index must be zero or greater.", aore);
}
catch(ArgumentException ae)
{
throw new ArgumentException("Not enough room in array to copy elements starting at index given.", ae);
}
}
잠재적으로 버그가 있을 수 있는 새로운 코드가 추가되었다는 점에서, 이것은 훨씬 더 심각합니다.그리고 우리는 내면의 예외로부터 아무것도 얻지 못합니다.하고 null 배열을 null 배열이 됩니다.ArgumentNullException
우리는 내부 예외를 조사하고 그것에 대한 전화를 배움으로써 아무것도 배우지 않을 것입니다._innerList.CopyTo
Null 배을통던졌습니다고를 .ArgumentNullException
.
여기서 우리는 다음과 같이 원하는 모든 것을 할 수 있습니다.
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentException ae)
{
throw ae;
}
}
사용자가 잘못된 인수를 사용하여 호출할 경우 발생할 것으로 예상되는 모든 예외는 해당 재전송에 의해 올바르게 발생합니다.두 줄중입니다. 이, 이 접근법이 작동하는 경우라고 판단하는 것이 잘못되었다는 것입니다. 우리가 이 접근 방식이 작동하는 경우라고 결정한 것이 잘못되었거나, 우리가 이 접근 방식을 사용한 것이 잘못되었습니다.ArgumentException
예외 유형이 검색한 대로입니다.그것은 캐치 블록이 가질 수 있는 유일한 두 가지 버그입니다.
저는 이 대부분 을 원한다는 것에 동의합니다.throw;
또는 해당 방법의 관점에서 문제와 보다 직접적으로 일치하도록 자신의 예외를 구성하려고 합니다.위와 같은 경우에는 이렇게 되던지는 것이 더 타당하고, 그 밖에도 많은 경우가 있습니다.예를 들어, 매우 다른 예를 들어, ATOM 파일 리더가 다음과 같이 구현된 경우FileStream
리고그.XmlTextReader
또는 XML을 이가 "" "XML"이라는 해야 합니다.AtomFileReader
은 그은던지것입다니는것을 입니다.FileNotFoundException
또는XmlException
그래서 그들은 비슷한 방식으로 다시 던질 가능성이 있습니다.
다음 두 가지를 결합할 수도 있습니다.
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentException ae)
{
throw ae;
}
catch(Exception ex)
{
//we weren't expecting this, there must be a bug in our code that put
//us into an invalid state, and subsequently let this exception happen.
LogException(ex);
throw;
}
}
.NET에서 예외를 다시 만들려면 항상 "throw;"를 사용해야 합니다.
기본적으로, MSIL(CIL)에는 "던지기"와 "다시 던지기"라는 두 가지 명령어가 있고 C#의 "던지기;"는 MSIL의 "던지기;"와 C#의 "던지기;"로 컴파일됩니다.기본적으로 "스스로 ex"가 스택 추적을 재정의하는 이유를 알 수 있습니다.
첫 번째가 더 좋습니다.두 번째를 디버그하고 호출 스택을 보면 원래 예외가 어디서 왔는지 알 수 없습니다.만약 당신이 정말로 재투입이 필요하다면, 콜 스택을 그대로 유지하기 위한 요령이 있습니다(검색 시도, 이전에 답변이 있었습니다).
저는 예외가 포착된 것과 같은 방식으로 던져지면 스택 추적이 보존되지 않는다는 것을 발견했습니다.
void testExceptionHandling()
{
try
{
throw new ArithmeticException("illegal expression");
}
catch (Exception ex)
{
throw;
}
finally
{
System.Diagnostics.Debug.WriteLine("finally called.");
}
}
사정에 따라 다르겠지.디버그 빌드에서는 가능한 한 적은 노력으로 원본 스택 추적을 보고 싶습니다.그런 경우에는 "던지기;"가 적합합니다.
그러나 릴리스 빌드에서 (a) 원래 스택 추적이 포함된 상태에서 오류를 기록하고, 기록이 완료되면 (b) 사용자가 더 이해할 수 있도록 오류 처리를 다시 포맷합니다.여기서 "예외 던지기"는 의미가 있습니다.오류를 다시 던지면 원래 스택 추적이 폐기되는 것은 사실이지만, 개발자가 아닌 사람은 스택 추적 정보를 보고 얻는 것이 없으므로 오류를 다시 던지면 됩니다.
void TrySuspectMethod()
{
try
{
SuspectMethod();
}
#if DEBUG
catch
{
//Don't log error, let developer see
//original stack trace easily
throw;
#else
catch (Exception ex)
{
//Log error for developers and then
//throw a error with a user-oriented message
throw new Exception(String.Format
("Dear user, sorry but: {0}", ex.Message));
#endif
}
}
"던지기:"와 "던지기 전에;"를 겨루는 질문의 표현 방식은 그것을 약간 빨간 청어로 만듭니다.실제 선택은 "던지기;"와 "던지기 예외" 중 하나입니다. 여기서 "던지기 예외;"는 "던지기 예외"의 특별한 경우일 가능성이 낮습니다.
언급URL : https://stackoverflow.com/questions/178456/what-is-the-proper-way-to-rethrow-an-exception-in-c
'programing' 카테고리의 다른 글
bash의 문자열을 이스케이프하는 명령 (0) | 2023.05.23 |
---|---|
npm 모듈의 모든 버전을 나열하는 방법은 무엇입니까? (0) | 2023.05.23 |
동일한 기본 키를 참조하는 두 개의 외부 키 (0) | 2023.05.23 |
편집기에서 재생할 때 Xcode Simulator 애니메이션이 매우 느림 (0) | 2023.05.23 |
IEnumberable 또는 Array 중 어떤 것을 선호해야 합니까? (0) | 2023.05.23 |