C #에서 예외를 다시 발생시키는 올바른 방법은 무엇입니까? [복제]
이 질문에는 이미 답변이 있습니다.
내 파트너와는 다른 방식으로 일을하면서 나오는 질문이 있습니다.
이것을하는 것이 낫습니다 :
try
{
...
}
catch (Exception ex)
{
...
throw;
}
아니면 이거:
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
그들은 같은 일을합니까? 하나는 다른 것보다 낫습니까?
예외를 다시 발생 시키려면 항상 다음 구문을 사용해야합니다. 그렇지 않으면 스택 추적이 멈 춥니 다.
throw;
"throw ex"로 인한 추적을 인쇄하면 예외의 실제 소스가 아니라 해당 명령문으로 끝납니다.
기본적으로 "throw ex"를 사용하는 것은 범죄 행위로 간주됩니다.
내가 선호하는 것은
try
{
}
catch (Exception ex)
{
...
throw new Exception ("Put more context here", ex)
}
이렇게하면 원래 오류는 유지되지만 개체 ID, 연결 문자열 등의 컨텍스트를 더 많이 넣을 수 있습니다. 종종 내 예외보고 도구에는보고 할 5 개의 연결 예외가 있으며, 각보고는 더 자세하게보고됩니다.
당신이 예외가 발생하는 경우 에서 변수 (두 번째 예) 스택 트레이스는 원래의 방법을 포함한다 예외 던졌다.
첫 번째 예에서 StackTrace는 현재 방법을 반영하도록 변경됩니다.
예:
static string ReadAFile(string fileName) {
string result = string.Empty;
try {
result = File.ReadAllLines(fileName);
} catch(Exception ex) {
throw ex; // This will show ReadAFile in the StackTrace
throw; // This will show ReadAllLines in the StackTrace
}
첫 번째는 예외의 원래 스택 추적을 유지하고 두 번째는 예외를 현재 위치로 대체합니다.
따라서 첫 번째는 BY FAR이 더 낫습니다.
나는 이것이 오래된 질문이라는 것을 알고 있지만 여기의 모든 답변에 동의하지 않기 때문에 대답 할 것입니다.
이제 대부분의 경우 평범한 throw
일을하고 싶거나 잘못된 일에 대해 가능한 많은 정보를 보존하거나 예외를 내부 예외로 포함 할 수있는 새 예외를 던지려 는 경우에 동의합니다. 그 원인이 된 내부 사건에 대해 알고 싶어하는 정도에 따라 다릅니다.
그러나 예외가 있습니다. 메소드가 다른 메소드를 호출하는 경우가 여러 가지 있으며 내부 호출에서 예외를 발생시키는 조건은 외부 호출에서 동일한 예외로 간주되어야합니다.
한 가지 예는 다른 컬렉션을 사용하여 구현 된 특수화 된 컬렉션입니다. a 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 배열을 전달하고를 수신 ArgumentNullException
하면 내부 예외를 검사하고에 대한 호출 _innerList.CopyTo
이 null 배열을 전달하고를 던졌다는 것을 학습하여 아무것도 배우지 않습니다 ArgumentNullException
.
여기에서 원하는 모든 것을 할 수 있습니다.
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentException ae)
{
throw ae;
}
}
사용자가 잘못된 인수로 호출하면 예외가 발생하여 다시 던질 때 올바르게 throw됩니다. 여기에 사용 된 논리에 버그가있는 경우 두 줄 중 하나에 있습니다.이 접근법이 작동하는 경우를 결정하는 데 잘못되었거나 ArgumentException
예외 유형을 찾는 데 잘못되었습니다 . catch 블록이 가질 수있는 유일한 버그는 두 가지입니다.
지금. 나는 여전히 대부분의 경우 평범한 throw;
것을 원하거나 문제의 방법의 관점에서 문제와 더 직접적으로 일치하도록 자신의 예외를 구성하고 싶다는 데 동의합니다 . 위와 같이 다시 던지는 것이 더 합리적 인 경우가 있으며 다른 많은 경우가 있습니다. 원자 파일 리더가 구현하는 경우 예는 매우 다른 예를 데리고 FileStream
와이 XmlTextReader
후는 아마도 그 클래스에서받은 정확히 같은 예외를 throw 할 것이다, 파일 오류 또는 유효하지 않은 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;
}
}
항상 "throw"를 사용해야합니다. .NET에서 예외를 다시 발생시키기 위해
이것을 참조하십시오 http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
기본적으로 MSIL (CIL)에는 "throw"및 "rethrow"와 C #의 "throw ex;"라는 두 가지 명령이 있습니다. MSIL의 "throw"및 C #의 "throw;"로 컴파일됩니다. -MSIL에 "다시 던져"! 기본적으로 "throw 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
}
}
"Throw :"vs. "Throw ex;" 그것은 약간 청어를 만듭니다. 진정한 선택은 "Throw;"입니다. "예외를 던지십시오." "예외 던지기"의 특별한 경우는 아닙니다.
참고 URL : https://stackoverflow.com/questions/178456/what-is-the-proper-way-to-re-throw-an-exception-in-c
도와주세요.
'development' 카테고리의 다른 글
우분투에서 ssh-add로 개인 키를 영구적으로 추가하는 방법은 무엇입니까? (0) | 2020.02.18 |
---|---|
여러 인수에 대한 Python 다중 처리 pool.map (0) | 2020.02.18 |
Mac OS X에서 adb 설정 (0) | 2020.02.18 |
배열 상태는 iOS 12 Safari에서 캐시됩니다. (0) | 2020.02.18 |
Java 8 Iterable.forEach () 대 foreach 루프 (0) | 2020.02.18 |