[c#] C #에서 ‘널 던지기’를 허용하는 이유는 무엇입니까?

특히 복잡한 예외 처리 코드를 작성하는 동안 누군가가 물었습니다. 예외 개체가 null이 아닌지 확인할 필요가 없습니까? 그리고 나는 물론 아니라고 말했지만 시도하기로 결정했습니다. 분명히 null을 던질 수 있지만 여전히 어딘가에서 예외로 변합니다.

왜 이것이 허용됩니까?

throw null;

이 스 니펫에서 고맙게도 ‘ex’는 null이 아니지만 그럴 수 있습니까?

try
{
  throw null;
}
catch (Exception ex)
{
  //can ex ever be null?

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}



답변

언어 사양은 유형의 표현식을 예상하고 System.Exception(따라서 null해당 컨텍스트에서 유효 함)이 표현식을 널이 아닌 것으로 제한하지 않기 때문입니다. 일반적으로 해당 표현식의 값이 맞는지 여부를 감지 할 수있는 방법은 null없습니다. 중지 문제를 해결해야합니다. null어쨌든 런타임은 케이스 를 처리해야 합니다. 보다:

Exception ex = null;
if (conditionThatDependsOnSomeInput)
    ex = new Exception();
throw ex;

물론 그들은 null리터럴을 무효화 하는 특정한 경우를 만들 수는 있지만 그다지 도움이되지 않을 것입니다. 그렇다면 왜 사양 공간을 낭비하고 적은 이익을 위해 일관성을 감소시킬까요?

면책 조항 (Eric Lippert에게 맞기 전) : 이것은 이 디자인 결정의이면에있는 이유에 대한 저의 추측입니다. 물론 저는 디자인 회의에 참석하지 않았습니다.)


두 번째 질문에 대한 답은 catch 절 내에서 잡힌 식 변수가 null 일 수 있는지 여부입니다. C # 사양은 다른 언어로 인해 null예외가 전파 될 수 있는지 여부에 대해 침묵하지만 예외가 전파되는 방식을 정의합니다.

catch 절 (있는 경우)은 예외에 대한 적절한 핸들러를 찾기 위해 나타나는 순서대로 검사됩니다. 예외 유형 또는 예외 유형의 기본 유형을 지정하는 첫 번째 catch 절 은 일치로 간주됩니다. 일반 catch 절은 모든 예외 유형에 대한 일치로 간주됩니다. […]

의 경우 null굵은 글씨는 거짓입니다. 따라서 순전히 C # 사양이 말하는 내용을 기반으로하지만 기본 런타임이 null을 throw하지 않는다고 말할 수는 없지만이 경우에도 일반 catch {}절에 의해서만 처리된다는 것을 확신 할 수 있습니다 .

CLI에서 C # 구현의 경우 ECMA 335 사양을 참조 할 수 있습니다. 이 문서는 CLI가 내부적으로 던지는 모든 예외를 정의하고 (아무것도 아님 null) 사용자 정의 예외 객체가 throw명령어에 의해 throw된다는 것을 언급합니다 . 해당 명령어에 대한 설명은 C # throw문과 거의 동일 합니다 (객체 유형을로 제한하지 않는다는 점 제외 System.Exception).

기술:

throw명령어는 O스택 에서 예외 객체 (type )를 throw하고 스택을 비 웁니다. 예외 메커니즘에 대한 자세한 내용은 파티션 I을 참조하십시오.
[참고 : CLI는 모든 개체의 throw를 허용하지만 CLS는 언어 상호 운용성을 위해 사용해야하는 특정 예외 클래스를 설명합니다. 끝 참고]

예외 :

System.NullReferenceException경우에 발생합니다 obj입니다 null.

단정:

올바른 CIL은 객체가 항상 null또는 객체 참조 (즉, 유형 O)인지 확인합니다.

나는 이것들이 잡힌 예외가 결코 없다는 결론을 내리기에 충분하다고 믿는다 null.


답변

분명히 null을 던질 수 있지만 여전히 어딘가에서 예외로 변합니다.

null개체 를 throw하려고 하면 (완전히 관련이없는) Null 참조 예외가 발생합니다.

던질 수있는 null이유를 묻는 것은 왜 이렇게 할 수 있는지 묻는 것과 같습니다.

object o = null;
o.ToString();


답변

여기 에서 가져온 :

C # 코드에서이 식을 사용하면 NullReferenceException이 발생합니다. 이는 throw- 문이 단일 매개 변수로 Exception 유형의 오브젝트를 필요로하기 때문입니다. 그러나이 객체는 내 예에서 null입니다.


답변

던지기가 그것을 감지하고 NullReferenceException으로 바꿀 것이기 때문에 C #에서 null을 던지는 것이 불가능할 수도 있지만, null을받을 수 있습니다. ‘ex’가 null이 될 것으로 예상) null 참조 예외가 발생하여 내 앱이 종료됩니다 (마지막 캐치이기 때문에).

따라서 C #에서 null을 throw 할 수는 없지만 netherworld는 null을 throw 할 수 있으므로 가장 바깥 쪽 catch (Exception ex)가이를 수신 할 준비를하는 것이 좋습니다. 참고로.


답변

나는 당신이 할 수 없다고 생각합니다-null을 던지려고 할 때 할 수 없으므로 null 참조 예외를 던지는 오류 경우에해야 할 일을합니다. 따라서 실제로 null을 던지는 것이 아니라 null을 던지지 않아 결과가 발생합니다.


답변

“.. 고맙게도 ‘ex’는 null이 아니지만 그럴 수 있습니까?”:

우리는 틀림없이 null 인 예외를 던질 수 없기 때문에 catch 절도 null 인 예외를 포착 할 필요가 없습니다. 따라서 ex는 null이 될 수 없습니다.

지금이 질문은 사실 이미 된 것을 볼 수 물었다 .


답변

예외에는 예외가 발생한 위치에 대한 세부 정보가 포함되어 있습니다. 생성자가 던질 위치를 알지 못하기 때문에 throw 메서드가 던지는 지점에서 해당 세부 정보를 객체에 주입하는 것이 합리적입니다. 즉, CLR이 NullReferenceException을 트리거하는 null에 데이터를 주입하려고합니다.

이것이 정확히 무슨 일이 일어나고 있는지 확실하지 않지만 현상을 설명합니다.

이것이 사실이라고 가정하면 (그리고 null을 던지는 것보다 ex를 null로 만드는 더 좋은 방법을 생각할 수 없습니다), 그것은 ex가 null이 될 수 없다는 것을 의미합니다.