[c#] C #에서 Null 매개 변수 검사

C #에서 null이 유효한 값이 아닌 모든 함수에 매개 변수 null 검사를 추가하는 데 좋은 이유 (더 나은 오류 메시지 제외)가 있습니까? 분명히 s를 사용하는 코드는 어쨌든 예외를 던질 것입니다. 그리고 이러한 검사는 코드를 유지 관리하기 더 느리고 어렵게 만듭니다.

void f(SomeType s)
{
  if (s == null)
  {
    throw new ArgumentNullException("s cannot be null.");
  }

  // Use s
}



답변

예, 그럴만 한 이유가 있습니다.

  • null이 무엇인지 정확히 식별합니다. NullReferenceException
  • 다른 조건이 값이 역 참조되지 않음을 의미하더라도 잘못된 입력에서 코드가 실패하게 만듭니다.
  • 메서드가 첫 번째 역 참조 전에 도달 할 수있는 다른 부작용을 갖기 전에 예외가 발생 하도록합니다.
  • 그것은 당신이 뭔가에 매개 변수를 전달하면 것을 확신 할 수 있다는 것을 의미합니다, 당신은 위반하지 않는 자신의 계약을
  • 그것은 당신의 방법의 요구 사항을 문서화합니다 ( 물론 코드 계약을 사용하는 것이 더 좋습니다)

이제 귀하의 이의 제기 :

  • 더 느립니다 : 이것이 실제로 코드의 병목 현상임을 발견 했습니까 , 아니면 추측하고 있습니까? Nullity 검사는 매우 빠르며 대부분의 경우 병목 현상이 발생 하지 않습니다.
  • 코드를 유지하기가 더 어려워집니다 . 그 반대라고 생각합니다. 매개 변수가 null 일 수 있는지 여부와 해당 조건이 적용된다는 확신이있는 경우 코드를 사용하는 것이 더 쉽다고 생각합니다 .

그리고 당신의 주장 :

분명히 s를 사용하는 코드는 어쨌든 예외를 던질 것입니다.

정말? 중히 여기다:

void f(SomeType s)
{
  // Use s
  Console.WriteLine("I've got a message of {0}", s);
}

를 사용 s하지만 예외는 발생하지 않습니다. snull이되는 것이 유효하지 않고 문제가 있음을 나타내는 경우 여기에서 예외가 가장 적절한 동작입니다.

이제 인수 유효성 검사를 어디에 두는 것은 다른 문제입니다. 자신의 클래스 내의 모든 코드를 신뢰하기로 결정할 수 있으므로 개인 메서드에 신경 쓰지 마십시오. 나머지 어셈블리를 신뢰하기로 결정할 수 있으므로 내부 메서드에 신경 쓰지 마십시오. 공용 메서드에 대한 인수의 유효성을 거의 확실하게 확인해야합니다.

참고 :의 단일 매개 변수 생성자 오버로드 ArgumentNullException는 매개 변수 이름이어야하므로 테스트는 다음과 같아야합니다.

if (s == null)
{
  throw new ArgumentNullException("s");
}

또는 확장 메소드를 생성하여 다소 간결하게 할 수 있습니다.

s.ThrowIfNull("s");

내 버전의 (일반) 확장 메서드에서는 null이 아닌 경우 원래 값을 반환하여 다음과 같은 내용을 작성할 수 있습니다.

this.name = name.ThrowIfNull("name");

너무 신경 쓰지 않으면 매개 변수 이름을 사용하지 않는 오버로드를 가질 수도 있습니다.


답변

나는 Jon의 의견에 동의하지만 여기에 한 가지 추가하겠습니다.

명시 적 null 검사를 추가 할 때에 대한 나의 태도는 다음 전제를 기반으로합니다.

  • 단위 테스트가 프로그램의 모든 명령문을 실행하는 방법이 있어야합니다.
  • throw진술은 진술 입니다.
  • 의 결과 if진술 입니다.
  • 따라서 운동 할 수있는 방법이 있어야한다 throw의를if (x == null) throw whatever;

해당 명령문을 실행할 수있는 방법없으면 테스트 할 수 없으며 Debug.Assert(x != null);.

해당 명령문을 실행할 수있는 방법이 있으면 명령문을 작성한 다음이를 실행하는 단위 테스트를 작성하십시오.

퍼블릭 타입의 퍼블릭 메서드는 이러한 방식으로 인수를 확인하는 것이 특히 중요합니다. 사용자가 어떤 미친 짓을할지 전혀 모릅니다. 그들에게 “이봐, 멍청 아, 잘못하고있어!” 가능한 한 빨리 예외.

대조적으로 private 형식의 private 메서드는 인수를 제어하는 ​​상황에있을 가능성이 훨씬 더 높으며 인수가 null이 아님을 강력하게 보장 할 수 있습니다. 그 불변성을 문서화하기 위해 어설 션을 사용하십시오.


답변

나는 이것을 1 년 동안 사용하고있다.

_ = s ?? throw new ArgumentNullException(nameof(s));

oneliner이고, 폐기 ( _)는 불필요한 할당이 없음을 의미합니다.


답변

명시 적없이 if검사, 파악하기가 매우 어려울 수 있습니다 무엇을 했다 null코드를 소유하지 않은 경우.

NullReferenceException소스 코드가없는 라이브러리 깊은 곳에서 정보 를 얻는다면 , 무엇을 잘못했는지 파악하는 데 많은 어려움이있을 것입니다.

이러한 if검사로 인해 코드가 눈에 띄게 느려지지는 않습니다.


받는 매개 변수 참고 ArgumentNullException생성자는 매개 변수 이름이 아닌 메시지입니다.
귀하의 코드는

if (s == null) throw new ArgumentNullException("s");

이 작업을 더 쉽게하기 위해 코드 조각을 작성했습니다.

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>Check for null arguments</Title>
            <Shortcut>tna</Shortcut>
            <Description>Code snippet for throw new ArgumentNullException</Description>
            <Author>SLaks</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
                <SnippetType>SurroundsWith</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>Parameter</ID>
                    <ToolTip>Paremeter to check for null</ToolTip>
                    <Default>value</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp"><![CDATA[if ($Parameter$ == null) throw new ArgumentNullException("$Parameter$");
        $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>


답변

null 개체를 매개 변수로 가져 오지 않도록 더 좋은 방법이 필요한 경우 코드 계약을 살펴볼 수 있습니다 .


답변

가장 큰 이점은 처음부터 방법의 요구 사항을 명확하게 할 수 있다는 것입니다. 이렇게하면 코드를 작업하는 다른 개발자에게 호출자가 메서드에 null 값을 보내는 것이 실제로 오류임을 분명히 알 수 있습니다.

이 검사는 다른 코드가 실행되기 전에 메서드 실행도 중지합니다. 즉, 미완성으로 남겨진 방법에 의해 수정되는 것에 대해 걱정할 필요가 없습니다.


답변

해당 예외가 발생하면 일부 디버깅이 절약됩니다.

ArgumentNullException은 null 인 “s”임을 명시 적으로 나타냅니다.

해당 검사가없고 코드가 작동하도록하면 해당 메서드의 식별되지 않은 줄에서 NullReferenceException이 발생합니다. 릴리스 빌드에서는 줄 번호가 없습니다!