ProgramingTip

C #에서 Null 매개 변수 검사

bestdevel 2020. 10. 20. 07:54
반응형

C #에서 Null 매개 변수 검사


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

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

  // Use s
}

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

  • null이 무엇인지 정확히 파악합니다. NullReferenceException
  • 조건이 값이 잘못된 입력에서 코드가 오류를 의미하지 않습니다.
  • 메서드가 첫 번째 역 참조하기 전에 도달 할 수있는 다른 부작용을 갖기 전에 예외가 발생 하도록합니다.
  • 그것은 당신이 뭔가에 자신의 계약을 전달하는 것을 확신 할 수 있다고 확신합니다.
  • 그것은 당신의 방법의 요구 사항을 문서화합니다 ( 물론 코드 계약을 사용하는 것이 더 좋습니다)

이제 귀하의 이의 제기 :

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

그리고 당신의 주장 :

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

정말? 중히 여기다 :

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);.

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

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

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


적없이 명시 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>

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

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

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


null 개체를 사용하는 경우에는 더 좋은 방법이 필요한 경우 코드 계약을 살펴볼 수 있습니다 .


가장 큰 이점은 처음부터 방법의 요구 사항을 명확하게 할 수 있다는 것입니다. 이것은 코드를 작업하는 다른 개발자들에게 호출자가 여러분의 메서드에 null 값을 보내는 것이 진정한 오류임을 분명히합니다.

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


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

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

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


int i = Age ?? 0;

따라서 귀하의 예를 들어 :

if (age == null || age == 0)

또는:

if (age.GetValueOrDefault(0) == 0)

또는:

if ((age ?? 0) == 0)

또는 삼항 :

int i = age.HasValue ? age.Value : 0;

원래 코드 :

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

  // Use s
}

다음과 같이 다시 작성하십시오.

void f(SomeType s)
{
  if (s == null) throw new ArgumentNullException(nameof(s));
}

[편집] 사용하여 다시 작성하는 이유 nameof는 쉽게 리팩토링 할 수 있기 때문입니다. 변수 이름이 s변경되면 디버깅 메시지도 업데이트되는 반면 변수 이름을 하드 코딩하면 시간이 지남에 따라 업데이트 될 때 결국 구식이됩니다. 업계에서 사용되는 좋은 관행입니다.

참고 URL : https://stackoverflow.com/questions/7585493/null-parameter-checking-in-c-sharp

반응형