문제

나는 사람들이 인수 없이 catch를 사용하는 것이 나쁜 형식이라고 말하는 것을 본 적이 있습니다. 특히 catch가 아무 것도 하지 않는 경우에는 더욱 그렇습니다.

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

그러나 이는 좋은 형식으로 간주됩니다.

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

내가 아는 한, finally 블록에 정리 코드를 넣는 것과 try..catch 블록 뒤에 정리 코드를 넣는 것 사이의 유일한 차이점은 try 블록에 return 문이 있는지 여부입니다(이 경우 finally의 정리 코드는 실행되지만 try..catch 이후의 코드는 실행되지 않습니다).

그렇지 않으면 마지막으로 무엇이 그렇게 특별한가요?

도움이 되었습니까?

해결책

가장 큰 차이점은 그 것입니다 try...catch 오류가 발생했다는 사실을 숨기고 예외를 삼키게됩니다. try..finally 정리 코드를 실행하면 예외가 계속 진행되며, 무엇을 해야하는지 알고있는 것으로 처리됩니다.

다른 팁

"마침내"는 "프로그램 상태가 정상인지 확인하기 위해 항상 수행해야 하는 작업"에 대한 설명입니다.따라서 예외로 인해 프로그램 상태가 중단될 가능성이 있는 경우 항상 하나를 갖는 것이 좋습니다.컴파일러는 또한 finally 코드가 실행되도록 하기 위해 많은 노력을 기울입니다.

"Catch"는 "이 예외를 복구할 수 있습니다"라는 진술입니다.실제로 수정할 수 있는 예외에서만 복구해야 합니다. 인수 없이 "이봐, 난 어떤 것에서도 복구할 수 있어!"라고 말하지만 거의 항상 사실이 아닙니다.

만약에 모든 예외로부터 복구하는 것이 가능했다면 이는 실제로 선언하려는 의도가 무엇인지에 대한 의미론적 문제가 될 것입니다.그러나 그렇지 않으며 거의 ​​확실하게 상위 프레임이 특정 예외를 처리하는 데 더 적합할 것입니다.따라서 finally를 사용하여 정리 코드를 무료로 실행하되 더 많은 지식을 갖춘 핸들러가 문제를 처리하도록 하세요.

하나의 한 줄이 예외를 던지면 알지 못할 것입니다.

코드의 첫 번째 블록을 사용하면 예외는 단순히 흡수, 프로그램의 상태가 잘못되었을 때도 프로그램은 계속 실행됩니다.

두 번째 블록에서는 예외가 될 것입니다 던졌습니다 그리고 거품 하지만 그만큼 reader.Close() 여전히 실행할 수 있습니다.

예외가 예상되지 않으면 시도하지 마십시오. 캐치 블록만으로도 프로그램이 나쁜 상태로 들어가면 나중에 디버그하기가 어려울 것입니다.

마침내 무슨 일이 있어도 실행됩니다. 따라서 Try Block이 성공하면 실행되면 Try Block이 실패하면 캐치 블록이 실행 된 다음 마지막으로 블록이 실행됩니다.

또한 다음 구성을 사용하는 것이 좋습니다.

using (StreamReader reader=new  StreamReader("myfile.txt"))
{
}

사용 명령문이 자동으로 시도 / 최종적으로 포장되고 스트림이 자동으로 닫힙니다. (실제로 예외를 잡으려면 사용 명령문 주위에 시도 / 캐치를 시도해야합니다).

다음 2 개의 코드 블록은 동일하지만 동일하지 않습니다.

try
{
  int i = 1/0; 
}
catch
{
  reader.Close();
  throw;
}

try
{
  int i = 1/0;
}
finally
{
  reader.Close();
}
  1. '마침내'는 의도-반사 코드입니다. 컴파일러와 다른 프로그래머 에게이 코드가 실행해야한다고 선언합니다.
  2. 캐치 블록이 여러 개 있고 정리 코드가 있으면 마지막으로 필요합니다. 마지막으로, 각 캐치 블록에서 정리 코드를 복제 할 것입니다. (건식 원리)

마지막으로 블록은 특별합니다. CLR은 캐치 블록과 별도로 마침내 블록을 사용하여 코드를 인식하고 처리하며 CLR은 최종 블록이 항상 실행되도록하기 위해 큰 길이로 이동합니다. 컴파일러의 구문 설탕만이 아닙니다.

나는 여기서 컨센서스로 보이는 것에 동의합니다. 빈 '캐치'는 시도 블록에서 발생했을 수있는 예외를 가리기 때문에 나쁘다.

또한, 가독성 관점에서, '시도'블록을 볼 때 해당 '캐치'진술이 있다고 가정합니다. '최종'블록에서 자원이 비 할당되도록하기 위해 '시도'만 사용하는 경우 다음을 고려할 수 있습니다. '사용'진술 대신에:

using (StreamReader reader = new StreamReader('myfile.txt'))
{
    // do stuff here
} // reader.dispose() is called automatically

idisposable을 구현하는 객체와 함께 '사용'문을 사용할 수 있습니다. 객체의 dispose () 메소드는 블록 끝에서 자동으로 호출됩니다.

try..finally 블록은 발생한 모든 예외를 계속 발생시킵니다.모두 finally 예외가 발생하기 전에 정리 코드가 실행되는지 확인하는 것입니다.

빈 catch가 있는 try..catch는 모든 예외를 완전히 소비하고 해당 예외가 발생했다는 사실을 숨깁니다.독자는 닫혀 있지만 올바른 일이 발생했는지는 알 수 없습니다.당신의 의도가 글을 쓰는 것이라면 어떨까요? 파일에?이 경우 코드의 해당 부분에 도달하지 못하고 마이파일.txt 비어있을 것입니다.모든 다운스트림 메소드가 이를 적절하게 처리합니까?빈 파일을 보면 예외가 발생했기 때문에 비어 있다고 정확하게 추측할 수 있습니까?예외를 발생시키고 뭔가 잘못하고 있음을 알리는 것이 더 좋습니다.

또 다른 이유는 이렇게 수행된 try..catch가 완전히 잘못되었기 때문입니다.이렇게함으로써 당신이 말하는 것은 "무슨 일이 있어도 나는 그것을 처리 할 수 ​​있습니다."입니다. 는 어때 StackOverflowException, 그 후에는 청소할 수 있나요?는 어때 OutOfMemoryException?일반적으로 예상하고 처리 방법을 알고 있는 예외만 처리해야 합니다.

사용 Try..Catch..Finally, 방법이 로컬로 예외를 처리하는 방법을 알고 있다면. 예외는 시도에서 발생하고 캐치로 처리되며 그 후에 정리가 마침내 이루어집니다.

방법이 예외를 처리하는 방법을 모르지만 사용되면 정리가 필요한 경우 Try..Finally

이에 따라 예외는 호출 방법으로 전파되고 호출 방법에 적절한 캐치 문이있는 경우 처리됩니다. 현재 방법 또는 호출 방법에 예외가 없으면 응용 프로그램이 충돌합니다.

에 의해 Try..Finally 호출 방법에 대한 예외를 전파하기 전에 로컬 청소가 수행되도록합니다.

잡아야 할 예외 유형이나 무엇을 해야하는지 모른다면 캐치 문을 가질 때는 아무런 의미가 없습니다. 상황에 대한 더 많은 정보가 무엇을 해야하는지 알 수있는 더 높은 발신자를 위해 남겨 두어야합니다.

예외가있는 경우에도 마침내 진술이 있어야하므로 예외가 발신자에게 버리기 전에 리소스를 정리할 수 있습니다.

가독적 인 관점에서 볼 때, 미래의 코드 리더에게 "여기에있는이 내용은 중요합니다. 어떤 일이 있어도해야 할 일이 필요합니다." 이것은 좋습니다.

또한 빈 캐치 진술은 그들에게 특정한 "냄새"가있는 경향이 있습니다. 개발자가 발생할 수있는 다양한 예외와 처리 방법을 통해 생각하지 않는다는 신호일 수 있습니다.

마지막으로 선택 사항입니다. 청소할 리소스가없는 경우 "마지막으로"블록을 가질 이유가 없습니다.

가져온 : 여기

방법을 성공적으로 실행하는 데있어 예외를 제기하고 포획하는 것이 일상적으로 발생해서는 안됩니다. 클래스 라이브러리를 개발할 때는 클라이언트 코드에 오류 조건을 테스트 할 수있는 기회가 있어야합니다. 예를 들어, System.io.Filestream은 읽기 메소드를 호출하기 전에 확인할 수있는 CANREAD 속성을 제공하여 다음 코드 스 니펫에 표시된 것처럼 잠재적 예외가 발생하지 않습니다.

dim str as stream = getStream () if (str.canread) 그런 다음 스트림 끝을 읽는 코드 if.

예외를 제기 할 수있는 특정 방법을 호출하기 전에 물체의 상태를 확인할지 여부에 대한 결정은 객체의 예상 상태에 따라 다릅니다. 존재하는 파일 경로와 읽기 모드에서 파일을 반환 해야하는 생성자를 사용하여 Filestream 객체가 생성되는 경우 CANREAD 속성을 점검 할 필요가 없습니다. 파일 스트림을 읽을 수 없다는 것은 통화가 이루어진 방법의 예상 행동을 위반하는 것이며 예외를 제기해야합니다. 대조적으로, 메소드가 읽을 수 없거나 읽을 수없는 FILESTREAM 참조를 반환하는 것으로 문서화되는 경우, 데이터를 읽으려고 시도하기 전에 CANREAD 속성을 점검하는 것이 좋습니다.

"예외까지 실행"코딩 기술을 사용하여 코딩 기술을 사용하면 캐스트가 실패하면 유효하지 않은 캐스트의 성능이 발생할 수있는 성능 영향을 설명하기 위해 캐스트가 실패하면 C#과 비교하여 캐스트가 실패하면 널을 반환합니다. 두 기술의 성능은 캐스트가 유효한 경우와 동일하지만 (테스트 8.05 참조) 캐스트가 유효하지 않은 경우 캐스트를 사용하는 경우 캐스트를 사용하는 것이 예외를 사용하는 경우에 사용하는 것보다 600 배 더 느립니다. 연산자로서 (테스트 8.06 참조). 예외적으로 던지는 기술의 고성능 영향에는 예외 객체의 후속 쓰레기 수집의 예외 및 비용을 할당, 던지기 및 포착 비용을 포함하여 예외를 던지는 즉각적인 영향이 이것이 높지 않다는 것을 의미합니다. 더 많은 예외가 발생함에 따라 빈번한 쓰레기 수집이 문제가되므로 예외 던지기 코딩 기술의 빈번한 사용의 전반적인 영향은 테스트 8.05와 유사합니다.

예외를 다시 줄이기 위해 캐치 절을 추가하는 것은 나쁜 관행입니다.

당신이 읽을 경우 프로그래머의 경우 C# 마지막으로 블록은 애플리케이션을 최적화하고 메모리 누출을 방지하는 설계라는 것을 이해할 것입니다.

CLR은 누출을 완전히 제거하지 않습니다 ... 프로그램이 원치 않는 객체에 대해 실수로 참조하는 경우 메모리 누출이 발생할 수 있습니다.

예를 들어 파일 또는 데이터베이스 연결을 열면 컴퓨터는 트랜잭션을 수용하기 위해 메모리를 할당하며, 폐기 또는 면밀한 명령이 실행되지 않으면 메모리가 유지되지 않습니다. 그러나 트랜잭션 중에 오류가 발생하면 절차 명령은 내부에 있지 않으면 종료되지 않습니다. try.. finally.. 차단하다.

catch 다릅니다 finally 관점에서, 캐치는 당신에게 오류를 스스로 처리/관리하거나 해석 할 수있는 방법을 제공하는 디자인이었습니다. "내가 나쁜 사람을 잡았 어, 내가 그들에게 뭘하고 싶어?"라고 말하는 사람으로 생각하십시오. 동안 finally 자원이 올바르게 배치되도록 설계되었습니다. 나쁜 사람이 있는지 여부에 관계없이 누군가가 당신의 재산이 여전히 안전했는지 확인할 것이라고 생각하십시오.

그리고 당신은 그 두 사람이 함께 일하도록 허용해야합니다.

예를 들어:

try
{
  StreamReader reader=new  StreamReader("myfile.txt");
  //do other stuff
}
catch(Exception ex){
 // Create log, or show notification
 generic.Createlog("Error", ex.message);
}
finally   // Will execute despite any exception
{
  reader.Close();
}

마지막으로, 캐치 명령문이 호출 프로그램까지 예외를 던지더라도 리소스를 정리할 수 있습니다. 빈 캐치 문이 포함 된 예제에는 차이가 거의 없습니다. 그러나 캐치에서 처리를 수행하고 오류를 던지거나 심지어 캐치가 전혀 없다면 마침내 여전히 실행됩니다.

글쎄, 당신이 처리하지 않는 예외를 포착하는 것은 나쁜 연습입니다. 체크 아웃 .NET 성능에 대한 5 장 ~에서 .NET 응용 프로그램 성능 및 확장 성 향상. 참고, 시도 블록 내부에 스트림을로드해야 할 것입니다. 그렇게하면 실패하면 관련 예외를 포착 할 수 있습니다. Try Block 외부에서 스트림을 만드는 것이 목적을 무너 뜨립니다.

아마도 여러 가지 이유 중에서 예외는 실행하기가 매우 느립니다. 이런 일이 많이 발생하면 실행 시간을 쉽게 구별 할 수 있습니다.

모든 예외를 포착하는 시도/캐치 블록의 문제점은 알려지지 않은 예외가 발생하면 프로그램이 이제 불확실한 상태에 있다는 것입니다. 이것은 실패 빠른 규칙에 완전히 반대합니다. 예외가 발생하면 프로그램이 계속되기를 원하지 않습니다. 위의 시도/캐치는 OutofMemoryExeceptions를 포착 할 것입니다. 그러나 그것은 분명히 당신의 프로그램이 실행되지 않을 것입니다.

시도/마침내 블록을 사용하면 빠르게 실패하면서 정리 코드를 실행할 수 있습니다. 대부분의 상황에서는 글로벌 수준에서 모든 예외 만 포착하여 로그인 한 다음 종료 할 수 있습니다.

예외가 발생하지 않는 한 예제 간의 효과적인 차이는 무시할 수 있습니다.

그러나 'try'절에서 예외가 발생하면 첫 번째 예제는 완전히 삼켜 줄 것입니다. 두 번째 예제는 다음 단계로의 통화 스택으로 예외를 제기하므로 명시된 예제의 차이점은 예외 (첫 번째 예)를 완전히 모호하게하고 다른 예제 (두 번째 예)는 나중에 처리 할 수있는 예외 정보를 유지한다는 것입니다. '마지막으로'절에서 컨텐츠를 실행하고 있습니다.

예를 들어, 예외를 던진 첫 번째 예제의 'Catch'조항에 코드를 넣어야한다면 (처음에 제기 된 것 또는 새 예제), Reader Cleanup Code는 결코 실행되지 않습니다. 마침내 실행됩니다 ~에 관계없이 '캐치'절에서 일어나는 일.

따라서 '캐치'와 '마지막'의 주요 차이점은 '마지막으로'블록 (몇 가지 드문 예외가 있음)의 내용을 고려할 수 있다는 것입니다. 보장 예상치 못한 예외에 직면하더라도 실행하는 반면, '캐치'절을 따르는 코드 (그러나 '마지막'조항 외부)는 그러한 보증을받지 않습니다.

또한 Stream 및 StreamReader는 모두 idisposable을 구현하며 '사용'블록으로 감싸 수 있습니다. '블록 사용'블록은 시도/마침내 ( 'Catch'없음)와 동등한 의미 론적이므로 예제는 다음과 같이 더 간절히 표현할 수 있습니다.

using (StreamReader reader = new  StreamReader("myfile.txt"))
{
  int i = 5 / 0;
}

... 스트리트 리더 인스턴스가 범위를 벗어날 때 폐쇄 및 폐기합니다. 도움이 되었기를 바랍니다.

시도 {…} catch {}가 항상 나쁘지는 않습니다. 일반적인 패턴은 아니지만 스레드 끝에 (아마도) 열린 소켓을 닫는 것과 같이 자원을 종료해야 할 때 사용하는 경향이 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top