다음을 통해 공유


Nullable 경고 해결

null 허용 경고의 목적은 애플리케이션 실행 시 System.NullReferenceException를 던질 가능성을 최소화하는 것입니다. 이 목표를 달성하기 위해 컴파일러는 정적 분석을 사용하고 코드에 null 참조 예외가 발생할 수 있는 구문이 있을 때 경고를 발생합니다. 형식 주석과 특성을 적용하여 컴파일러에 정적 분석에 대한 정보를 제공합니다. 이러한 주석과 특성은 인수, 매개 변수 및 형식 멤버의 Null 허용 여부를 설명합니다. 이 문서에서는 컴파일러가 정적 분석에서 생성하는 nullable 경고를 해결하기 위한 다양한 기술을 알아봅니다. 여기에 설명된 기술은 일반 C# 코드에 대한 것입니다. null 허용 참조 형식 작업에서 null 허용 참조 형식 및 Entity Framework 코어를 사용하여 작업하는 방법을 알아봅니다.

nullable 참조 형식, 연산자 ?!을 포함하여, nullable 컨텍스트가 enable 또는 annotations로 설정된 경우에만 허용됩니다. 프로젝트 파일의 Nullable컴파일러 옵션 사용하거나 소스 코드에서 #nullable pragma를 사용하여 nullable 컨텍스트를 설정할 수 있습니다.

이 문서에서는 다음 컴파일러 경고에 대해 설명합니다.

  • CS8597 - throw된 값은 null일 수 있습니다.
  • CS8598 - 이 컨텍스트에서는 제거 연산자가 허용되지 않습니다
  • CS8600 - null 리터럴이나 null일 가능성이 있는 값을 null을 허용하지 않는 형식으로 변환합니다.
  • CS8601 - null 참조로 할당될 가능성이 있습니다.
  • CS8602 - 가능한 null 참조의 역참조.
  • CS8603 - null 참조가 반환될 가능성이 있습니다.
  • CS8604 - 매개 변수에 대한 가능한 null 참조 인수입니다.
  • CS8605 - 잠재적으로 null 값을 해제합니다.
  • CS8607 - 가능한 null 값은 [NotNull] 또는 [DisallowNull]로 표시된 형식에 사용할 수 없습니다.
  • CS8608 - 형식에 있는 참조 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다.
  • CS8609 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다.
  • CS8610 - 형식 매개 변수에 있는 참조 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다.
  • CS8611 - 형식 매개 변수에 있는 참조 형식의 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
  • CS8612 - 형식에 있는 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다.
  • CS8613 - 반환 형식에서 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다.
  • CS8614 - 매개변수 형식의 참조 유형의 null 가능성 여부가 암묵적으로 구현된 멤버와 일치하지 않습니다.
  • CS8615 - 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다.
  • CS8616 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다.
  • CS8617 - 매개 변수 형식의 참조 형식의 null 허용성이 구현된 멤버와 일치하지 않습니다.
  • CS8618 - null을 허용하지 않는 변수는 생성자에서 벗어날 때 null이 아닌 값을 포함해야 합니다. 그 변수를 null 허용으로 선언하는 것이 좋습니다.
  • CS8619 - 값의 참조 형식 Null 허용 여부가 대상 유형과 일치하지 않습니다.
  • CS8620 - 참조 형식의 Null 허용 여부가 다르기 때문에 매개 변수에 인수를 사용할 수 없습니다.
  • CS8621 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 대상 대리자와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8622 - 매개 변수 형식에서 참조 형식의 Null 허용 여부가 대상 대리자와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8623 - System.Runtime.CompilerServices.NullableAttribute 명시적 애플리케이션은 허용되지 않습니다.
  • CS8624 - 참조 형식의 Null 허용 여부가 다르기 때문에 인수를 출력으로 사용할 수 없습니다.
  • CS8625 - null 리터럴을 null을 허용하지 않는 참조 형식으로 변환할 수 없습니다.
  • CS8628 - 개체를 만들 때 nullable 참조 형식을 사용할 수 없습니다.
  • CS8629 - Null 허용 값 형식은 null일 수 있습니다.
  • CS8631 - 제네릭 형식 또는 메서드에서 형식을 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 제약 조건 형식과 일치하지 않습니다.
  • CS8632 - nullable 참조 형식에 대한 주석은 #nullable 주석 컨텍스트 내의 코드에서만 사용해야 합니다.
  • CS8633 - 메서드 형식 매개 변수 제약 조건의 Null 허용 여부가 인터페이스 메서드 형식 매개 변수 제약 조건과 일치하지 않습니다. 명시적 인터페이스 구현을 대신 사용하세요.
  • CS8634 - 이 형식은 제네릭 형식 또는 메서드에서 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 '클래스' 제약 조건과 일치하지 않습니다.
  • CS8636 - 잘못된 옵션입니다 /nullable; disable, enable, warnings 또는 annotations 중 하나여야 합니다
  • CS8637 - 예상 enable, disable또는 restore
  • CS8639 - typeof 연산자는 nullable 참조 형식 사용할 수 없습니다.
  • CS8643 - 명시적 인터페이스 지정자에 있는 참조 형식의 Null 허용 여부가 해당 형식으로 구현된 인터페이스와 일치하지 않습니다.
  • CS8644 - 형식이 인터페이스 멤버를 구현하지 않습니다. 기본 형식으로 구현된 인터페이스의 참조 형식의 Null 허용 여부가 일치하지 않습니다.
  • CS8645 - 참조 형식의 Null 허용 여부가 다른 형식의 인터페이스 목록에 멤버가 이미 나열되어 있습니다.
  • CS8655 - switch 식은 일부 null 입력을 처리하지 않습니다(완전하지는 않음).
  • CS8667 - 부분 메서드 선언의 형식 매개 변수 제약 조건에 일관되지 않은 Null 허용 여부가 있습니다.
  • CS8670 - 개체 또는 컬렉션 이니셜라이저가 null일 수 있는 멤버를 암시적으로 역참조합니다.
  • CS8714 - 이 형식은 제네릭 형식 또는 메서드에서 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 'notnull' 제약 조건과 일치하지 않습니다.
  • CS8762 - 종료 시 매개 변수에 null이 아닌 값이 있어야 합니다.
  • CS8763 - [DoesNotReturn]으로 표시된 메서드는 반환되어서는 안 됩니다.
  • CS8764 - 반환 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8765 - 매개 변수 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8766 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8767 - 매개 변수 형식의 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8768 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8769 - 매개 변수 형식의 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8770 - 메서드에 구현되거나 재정의된 멤버와 일치하는 [DoesNotReturn] 어노테이션이 없습니다.
  • CS8774 - 멤버 종료 시 null이 아닌 값이 있어야 합니다.
  • CS8776 - 이 특성에서는 멤버를 사용할 수 없습니다.
  • CS8775 - 멤버 종료 시 null이 아닌 값이 있어야 합니다.
  • CS8777 - 종료 시 매개 변수에 null이 아닌 값이 있어야 합니다.
  • CS8819 - 반환 형식에서 참조 형식의 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
  • CS8824 - 매개 변수가 null이 아니기 때문에 종료 시 매개 변수에 null이 아닌 값이 있어야 합니다.
  • CS8825 - 매개 변수가 null이 아니기 때문에 반환 값은 null이 아니어야 합니다.
  • CS8847 - switch 식은 일부 null 입력을 처리하지 않습니다(전체 아님). 그러나 'when' 절이 있는 패턴은 이 값과 성공적으로 일치할 수 있습니다.

메모

정적 분석은 특정 시나리오에서 메서드에 액세스하는 순서와 예외를 throw하지 않고 메서드가 성공적으로 완료되는지 여부를 항상 추론할 수 없습니다. 이러한 알려진 함정은 알려진 함정 섹션에서 잘 설명되어 있습니다.

다음 5가지 기술 중 하나를 사용하여 거의 모든 경고를 해결합니다.

  • nullable 컨텍스트 구성
  • 필요한 null 검사를 추가합니다.
  • nullable 주석을 ? 또는 !에 추가하거나 제거하기.
  • Null 의미 체계를 설명하는 특성을 추가합니다.
  • 변수를 올바르게 초기화하는 중입니다.

nullable 참조 형식에 익숙하지 않다면, nullable 참조 형식의 개요 는 이러한 형식이 해결하는 문제와 코드에서 발생할 수 있는 실수에 대한 경고를 제공하는 방법에 대한 배경 지식을 제공합니다. nullable 참조 형식으로 마이그레이션하는 지침을 확인하여 기존 프로젝트에서 nullable 참조 형식을 사용하도록 설정하는 방법에 대해 자세히 알아볼 수도 있습니다.

nullable 컨텍스트 구성

다음 경고는 nullable 컨텍스트를 올바르게 설정하지 않았음을 나타냅니다.

  • CS8632 - nullable 참조 형식에 대한 주석은 #nullable 주석 컨텍스트 내의 코드에서만 사용해야 합니다.
  • CS8636 - 잘못된 옵션입니다. /nullable에는 disable, enable, warnings 또는 annotations만 사용할 수 있습니다.
  • CS8637 - 예상 enable, disable또는 restore

잘못된 주석 구문

이러한 오류 및 경고는 ! 또는 ? 주석의 사용이 잘못되었음을 나타냅니다.

  • CS8598 - 이 컨텍스트에서는 억제 연산자가 허용되지 않습니다
  • CS8623 - System.Runtime.CompilerServices.NullableAttribute 명시적 애플리케이션은 허용되지 않습니다.
  • CS8628 - 개체를 만들 때 nullable 참조 형식을 사용할 수 없습니다.
  • CS8639 - typeof 연산자는 nullable 참조 형식에 사용할 수 없습니다.

선언의 ? 주석은 변수가 null일 수 있음을 나타냅니다. 다른 런타임 형식을 나타내지 않습니다. 다음 선언은 모두 동일한 런타임 형식입니다.

string s1 = "a string";
string? s2 = "another string";

? null 값에 대한 기대에 대한 컴파일러의 힌트입니다.

식의 ! 주석은 식이 안전하다는 것을 알고 있으며 null이 아닌 것으로 간주되어야 했음을 나타냅니다.

  • 코드의 System.Runtime.CompilerServices.NullableAttribute 아닌 이러한 주석을 사용해야 합니다.
  • ? 형식이 아닌 주석이므로 typeof또는 new 식과 함께 사용할 수 없습니다.
  • ! 연산자는 변수 식이나 메서드 그룹에 적용할 수 없습니다.
  • ! 연산자는 obj.Field!.Method()같은 멤버 액세스 연산자의 왼쪽에 적용할 수 없습니다.

가능한 null 역참조

이 경고 집합은 null-statemaybe-null인 변수를 역참조하고 있음을 알려 줍니다. 이러한 경고는 다음과 같습니다.

  • CS8602 - 가능성이 있는 null 참조의 역참조.
  • CS8670 - 개체 또는 컬렉션 이니셜라이저가 null일 수 있는 멤버를 암시적으로 역참조합니다.

다음 코드는 위의 각 경고에 대한 예를 보여 줍니다.

class Container
{
    public List<string>? States { get; set; }
}

internal void PossibleDereferenceNullExamples(string? message)
{
    Console.WriteLine(message.Length); // CS8602

    var c = new Container { States = { "Red", "Yellow", "Green" } }; // CS8670
}

앞의 예제에서, 경고는 Container, cStates 속성에 대해 null 값을 가질 수 있기 때문입니다. null일 수 있는 컬렉션에 새 상태를 할당하면 경고가 발생합니다.

이러한 경고를 제거하려면 해당 변수를 역참조하기 전에 해당 변수의 null-statenot-null로 변경하는 코드를 추가해야 합니다. 컬렉션 이니셜라이저 경고는 발견하기 어려울 수 있습니다. 컴파일러는 이니셜라이저가 컬렉션에 요소를 추가할 때 maybe-null인 컬렉션을 검색합니다.

대부분의 경우 변수를 역참조하기 전에 변수가 null이 아닌지 확인하여 이러한 경고를 수정할 수 있습니다. message 매개 변수를 역참조하기 전에 null 검사를 추가하는 다음 예제를 살펴보겠습니다.

void WriteMessageLength(string? message)
{
    if (message is not null)
    {
        Console.WriteLine(message.Length);
    }
    
}

다음 예에서는 States에 대한 지원 스토리지를 초기화하고 set 접근자를 제거합니다. 클래스 소비자는 컬렉션의 콘텐츠를 수정할 수 있으며 컬렉션의 스토리지는 절대로 null이 아닙니다.

class Container
{
    public List<string> States { get; } = new();
}

이러한 경고를 받을 때 그것들이 오탐일 가능성도 있습니다. null을 테스트하는 프라이빗 유틸리티 메서드가 있을 수 있습니다. 컴파일러는 메서드가 null 검사를 제공한다는 사실을 모릅니다. 프라이빗 유틸리티 메서드인 IsNotNull을 사용하는 다음 예를 고려합니다.

public void WriteMessage(string? message)
{
    if (IsNotNull(message))
        Console.WriteLine(message.Length);
}

컴파일러는 정적 분석에서 messagenull수 있다고 판단하기 때문에 속성 message.Length 작성할 때 null을 역참조할 수 있음을 경고합니다. IsNotNull이 null 검사를 제공하며, true을 반환할 때 messagenull 상태은 null이 아닌 여야 합니다. 컴파일러에게 이러한 팩트를 알려 주어야 합니다. 한 가지 방법은 널 허용 연산자인 !을 사용하는 것입니다. 다음 코드와 일치하도록 WriteLine 문을 변경할 수 있습니다.

Console.WriteLine(message!.Length);

null 허용 연산자는 이 적용되지 않은 maybe-null인 경우에도 ! 식을 만듭니다. 이 예에서 더 나은 솔루션은 IsNotNull의 서명에 특성을 추가하는 것입니다.

private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;

System.Diagnostics.CodeAnalysis.NotNullWhenAttribute는 메서드가 obj를 반환할 때 매개 변수에 사용된 인수가 true임을 컴파일러에 알립니다. 메서드가 false를 반환하면 인수는 메서드가 호출되기 전과 동일한 null-state를 갖게 됩니다.

메서드와 속성이 null-state에 미치는 영향을 설명하는 데 사용할 수 있는 다양한 특성 집합이 있습니다. null 허용 정적 분석 특성에 대한 언어 참조 문서에서 이에 대해 알아볼 수 있습니다.

maybe-null 변수 역참조에 대한 경고를 수정하려면 다음 세 가지 기술 중 하나가 필요합니다.

  • 누락된 null 검사를 추가합니다.
  • 컴파일러의 null-state 정적 분석에 영향을 미치도록 API에 null 분석 특성을 추가합니다. 이러한 특성은 메서드 호출 후 반환 값이나 인수가 maybe-null 또는 not-null이어야 하는 경우를 컴파일러에 알립니다.
  • 상태가 null이 아닌 식에 null 용서 연산자 ! 적용합니다.

null을 허용하지 않는 참조에 null이 할당될 가능성이 있습니다.

이 경고 집합은 null-statemaybe-null인 식에 null을 허용하지 않는 형식의 변수를 할당하고 있음을 알려 줍니다. 이러한 경고는 다음과 같습니다.

  • CS8597 - 던져진 값은 null일 수 있습니다.
  • CS8600 - null 리터럴 또는 가능한 null 값을 null을 허용하지 않는 형식으로 변환합니다.
  • CS8601 - null 참조를 할당할 가능성이 있습니다.
  • CS8603 - null 참조가 반환될 가능성이 있습니다.
  • CS8604 - 매개 변수에 대한 가능한 null 참조 인수입니다.
  • CS8605 - 가능한 null 값을 unboxing합니다.
  • CS8625 - null 리터럴을 null을 허용하지 않는 참조 형식으로 변환할 수 없습니다.
  • CS8629 - Null 허용 값 형식은 null일 수 있습니다.

null을 허용하지 않는 변수에 maybe-null인 식을 할당하려고 하면 컴파일러는 이러한 경고를 표시합니다. 예시:

string? TryGetMessage(int id) => "";

string msg = TryGetMessage(42);  // Possible null assignment.

다양한 경고는 할당, unboxing 할당, 반환 문, 메서드에 대한 인수, throw 식 등 코드에 대한 세부 정보를 제공함을 나타냅니다.

이러한 경고를 해결하려면 세 가지 작업 중 하나를 수행할 수 있습니다. 하나는 ? 주석을 추가하여 변수를 null 허용 참조 형식으로 만드는 것입니다. 이러한 변경으로 인해 다른 경고가 발생할 수 있습니다. null을 허용하지 않는 참조에서 null을 허용하는 참조로 변수를 변경하면 기본 null-statenot-null에서 maybe-null으로 변경됩니다. 컴파일러의 정적 분석은 변수를 역참조하는 인스턴스를 찾습니다.

다른 작업은 할당문의 오른쪽 항목이 not-null임을 컴파일러에 지시합니다. 다음 예와 같이 오른쪽에 있는 식은 할당 전에 null 검사를 수행할 수 있습니다.

string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";

이전 예에서는 메서드의 반환 값 할당을 보여 줍니다. 메서드가 null이 아닌 값을 반환하는 시기를 나타내기 위해 메서드(또는 속성)에 주석을 추가합니다. System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute는 입력 인수가 not-null일 때 반환 값이 not-null임을 지정하는 경우가 많습니다. 또 다른 대안은 null 허용 연산자인 !을 오른쪽에 추가하는 것입니다.

string msg = TryGetMessage(42)!;

not-null 변수에 maybe-null 식을 할당하는 데 대한 경고를 수정하려면 다음 네 가지 기술 중 하나가 필요합니다.

  • 할당의 왼쪽을 nullable 형식으로 변경합니다. 이 작업은 해당 변수를 역참조할 때 새 경고를 발생시킬 수 있습니다.
  • 할당 전에 null 검사를 제공합니다.
  • 할당문의 오른쪽 값을 생성하는 API에 주석을 답니다.
  • 할당의 오른쪽에 null 허용 연산자를 추가합니다.

null을 허용하지 않는 참조가 초기화되지 않았습니다.

이 경고 집합은 null-statemaybe-null인 식에 null을 허용하지 않는 형식의 변수를 할당하고 있음을 알려 줍니다. 이러한 경고는 다음과 같습니다.

  • CS8618 - null을 허용하지 않는 변수는 생성자를 종료할 때 null이 아닌 값을 포함해야 합니다. null 허용으로 선언하는 것이 좋습니다.
  • CS8762 - 종료 시 매개 변수에 null이 아닌 값이 있어야 합니다.

다음 클래스를 예로 생각해 볼 수 있습니다.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

FirstName이나 LastName 모두 초기화가 보장되지 않습니다. 이 코드가 새로운 코드라면 public 인터페이스를 변경하는 것이 좋습니다. 앞의 예제는 다음과 같이 업데이트될 수 있습니다.

public class Person
{
    public Person(string first, string last)
    {
        FirstName = first;
        LastName = last;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

이름을 설정하기 전에 Person 개체를 만들어야 하는 경우 null이 아닌 기본값을 사용하여 속성을 초기화할 수 있습니다.

public class Person
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
}

또 다른 대안은 해당 멤버를 nullable 참조 형식으로 변경하는 것입니다. 이름에 Person을 허용해야 하는 경우 null 클래스는 다음과 같이 정의될 수 있습니다.

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}

기존 코드는 경우에 따라 컴파일러에 해당 멤버에 대한 null 의미 체계를 알리기 위해 다른 변경 내용이 필요합니다. 여러 생성자가 있을 수 있으며 클래스에는 하나 이상의 멤버를 초기화하는 프라이빗 도우미 메서드가 있습니다. 초기화 코드를 단일 생성자로 이동하고 모든 생성자가 공통 초기화 코드를 사용하여 해당 생성자를 호출하도록 할 수 있습니다. 또는 System.Diagnostics.CodeAnalysis.MemberNotNullAttributeSystem.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute 특성을 사용할 수 있습니다. 이러한 특성은 메서드가 반환된 후 멤버가 null이 아닌 컴파일러에 알릴 수 있습니다. 다음 코드에서는 각 예제를 보여 줍니다. Person 클래스는 다른 모든 생성자가 호출하는 공통 생성자를 사용합니다. Student 클래스에는 System.Diagnostics.CodeAnalysis.MemberNotNullAttribute 특성으로 주석이 달린 도우미 메서드가 있습니다.


using System.Diagnostics.CodeAnalysis;

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public Person() : this("John", "Doe") { }
}

public class Student : Person
{
    public string Major { get; set; }

    public Student(string firstName, string lastName, string major)
        : base(firstName, lastName)
    {
        SetMajor(major);
    }

    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
        SetMajor();
    }

    public Student()
    {
        SetMajor();
    }

    [MemberNotNull(nameof(Major))]
    private void SetMajor(string? major = default)
    {
        Major = major ?? "Undeclared";
    }
}

마지막으로 null 허용 연산자를 사용하여 멤버가 다른 코드에서 초기화되었음을 나타낼 수 있습니다. 또 다른 예로 Entity Framework Core 모델을 나타내는 다음 클래스를 생각해 볼 수 있습니다.

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; } = null!;
}

DbSet 속성이 null!으로 초기화됩니다. 이는 속성이 not-null 값으로 설정되었음을 컴파일러에 알립니다. 실제로 기본 DbContext는 집합 초기화를 수행합니다. 컴파일러의 정적 분석에서는 이를 포착하지 못합니다. Null 허용 참조 형식 및 Entity Framework Core 작업에 대한 자세한 내용은 EF Core에서 Null 허용 참조 형식 작업 문서를 참조하세요.

null을 허용하지 않는 멤버를 초기화하지 않는다는 경고를 수정하려면 다음 네 가지 기술 중 하나가 필요합니다.

  • null을 허용하지 않는 모든 멤버가 초기화되도록 생성자 또는 필드 이니셜라이저를 변경합니다.
  • 하나 이상의 멤버를 nullable 형식으로 변경합니다.
  • 할당된 멤버를 나타내기 위해 도우미 메서드에 주석을 답니다.
  • 멤버가 다른 코드에서 초기화되었음을 나타내려면 null!에 이니셜라이저를 추가합니다.

Null 허용 여부 선언의 불일치

많은 경고는 메서드, 대리자 또는 형식 매개 변수에 대한 서명 간의 Null 허용 여부 불일치를 나타냅니다.

  • CS8608 - 형식 내에서 참조 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다.
  • CS8609 - 반환 형식에서 참조 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다.
  • CS8610 - 형식 매개 변수에 있는 참조 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다.
  • CS8611 - 형식 매개 변수에 있는 참조 형식의 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
  • CS8612 - 형식에 있는 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다.
  • CS8613 - 반환 형식에서 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다.
  • CS8614 - 매개변수 형식에서의 참조 유형의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다.
  • CS8615 - 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다.
  • CS8616 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다.
  • CS8617 - 매개 변수의 참조 유형의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다.
  • CS8619 - 값 내의 참조 유형의 null 허용성이 대상 유형과 일치하지 않습니다.
  • CS8620 - 참조 형식의 Null 허용 여부가 다르기 때문에 매개 변수에 인수를 사용할 수 없습니다.
  • CS8621 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 대상 대리자와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8622 - 매개 변수 형식에서 참조 형식의 Null 허용 여부가 대상 대리자와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8624 - 참조 형식의 Null 허용 여부가 다르기 때문에 인수를 출력으로 사용할 수 없습니다.
  • CS8631 - 이 형식은 제네릭 형식 또는 메서드에서 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 제약 조건 형식과 일치하지 않습니다.
  • CS8633 - 메서드 형식 매개 변수 제약 조건의 Null 허용 여부가 인터페이스 메서드 형식 매개 변수 제약 조건과 일치하지 않습니다. 명시적 인터페이스 구현을 대신 사용하세요.
  • CS8634 - 이 형식은 제네릭 형식 또는 메서드에서 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 '클래스' 제약 조건과 일치하지 않습니다.
  • CS8643 - 명시적 인터페이스 지정자에 있는 참조 형식의 Null 허용 여부가 해당 형식으로 구현된 인터페이스와 일치하지 않습니다.
  • CS8644 - 형식이 인터페이스 멤버를 구현하지 않습니다. 기본 형식으로 구현된 인터페이스의 참조 형식의 Null 허용 여부가 일치하지 않습니다.
  • CS8645 - 참조 형식의 Null 허용 여부가 다른 형식의 인터페이스 목록에 멤버가 이미 나열되어 있습니다.
  • CS8667 - 형식 매개 변수 제약 조건에서 부분 메서드 선언의 Null 허용 여부에 일관성이 없습니다.
  • CS8714 - 이 형식은 제네릭 형식 또는 메서드에서 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 'notnull' 제약 조건과 일치하지 않습니다.
  • CS8764 - 반환 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8765 - 매개 변수 형식의 Null 허용 여부가 재정의된 멤버와 일치하지 않습니다(Null 허용 여부 속성 때문일 수 있음).
  • CS8766 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 암시적으로 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8767 - 매개변수 유형에서 참조 형식의 null 가능성이 해당 멤버의 암묵적 구현과 일치하지 않습니다(아마도 null 가능성 특성 때문일 수 있습니다).
  • CS8768 - 반환 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8769 - 매개 변수 형식에 있는 참조 형식의 Null 허용 여부가 구현된 멤버와 일치하지 않습니다(Null 허용 여부 특성 때문일 수 있음).
  • CS8819 - 반환 형식에서 참조 형식의 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.

다음 코드는 CS8764를 보여 줍니다.

public class B
{
    public virtual string GetMessage(string id) => string.Empty;
}
public class D : B
{
    public override string? GetMessage(string? id) => default;
}

앞의 예에서는 기본 클래스의 virtual 메서드와 Null 허용 여부가 다른 override를 보여 줍니다. 기본 클래스는 null을 허용하지 않는 문자열을 반환하지만 파생 클래스는 null을 허용하는 문자열을 반환합니다. stringstring?이 반대인 경우 파생 클래스가 더 제한적이므로 허용됩니다. 마찬가지로 매개 변수 선언도 일치해야 합니다. 재정의 메서드의 매개 변수는 기본 클래스가 허용하지 않는 경우에도 null을 허용할 수 있습니다.

다른 상황에서도 이러한 경고가 발생할 수 있습니다. 인터페이스 메서드 선언과 해당 메서드의 구현이 일치하지 않습니다. 또는 대리자 형식과 해당 대리자의 식이 다릅니다. 형식 매개 변수와 형식 인수는 null 허용 여부가 다릅니다.

이러한 경고를 해결하려면 적절한 선언을 업데이트합니다.

코드가 특성 선언과 일치하지 않습니다.

앞의 섹션에서는 null 허용 정적 분석 특성을 사용하여 컴파일러에 코드의 null 의미 체계를 알리는 방법에 대해 설명했습니다. 코드가 해당 특성의 약속을 준수하지 않으면 컴파일러는 경고합니다.

  • CS8607 - 가능한 null 값은 [NotNull] 또는 [DisallowNull]로 표시된 형식에 사용할 수 없습니다.
  • CS8763 - [DoesNotReturn]으로 표시된 메서드는 반환되어서는 안 됩니다.
  • CS8770 - 메서드에 구현되거나 재정의된 멤버와 일치하는 [DoesNotReturn] 주석이 없습니다.
  • CS8774 - 멤버 종료 시 null이 아닌 값이 있어야 합니다.
  • CS8775 - 멤버 종료 시 null이 아닌 값이 있어야 합니다.
  • CS8776 - 이 특성에서는 멤버를 사용할 수 없습니다.
  • CS8777 - 종료 시 매개 변수에 null이 아닌 값이 있어야 합니다.
  • CS8824 - 매개 변수가 null이 아니기 때문에 종료 시 매개 변수에 null이 아닌 값이 있어야 합니다.
  • CS8825 - 매개 변수가 null이 아니기 때문에 반환 값은 null이 아니어야 합니다.

다음 방법을 고려하십시오.

public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
    message = null;
    return true;

}

message 매개 변수가 할당되고null 메서드가 true를 반환하기 때문에 컴파일러는 경고를 생성합니다. NotNullWhen 특성은 이러한 일이 발생해서는 안 된다는 것을 나타냅니다.

이러한 경고를 해결하려면 적용된 특성의 예상과 일치하도록 코드를 업데이트합니다. 특성 또는 알고리즘을 변경할 수 있습니다.

모든 경우를 포괄하는 switch 식

switch 식은 완전해야 합니다. 즉, 모든 입력 값을 처리해야 합니다. Null을 허용하지 않는 참조 형식의 경우에도 null 값을 고려해야 합니다. null 값이 처리되지 않으면 컴파일러는 경고를 발급합니다.

  • CS8655 - switch 식은 일부 null 입력을 처리하지 않습니다(완전하지는 않음).
  • CS8847 - switch 식은 일부 null 입력을 처리하지 않습니다(전체 아님). 그러나 'when' 절이 있는 패턴은 이 값과 성공적으로 일치할 수 있습니다.

다음 코드 예는 이 조건을 보여 줍니다.

int AsScale(string status) =>
    status switch
    {
        "Red" => 0,
        "Yellow" => 5,
        "Green" => 10,
        { } => -1
    };

입력 식은 string이 아닌 string?입니다. 컴파일러는 여전히 이 경고를 생성합니다. { } 패턴은 null이 아닌 모든 값을 처리하지만 null과 일치하지 않습니다. 이러한 오류를 해결하려면 명시적인 null 사례를 추가하거나 { }_(무시 항목) 패턴으로 바꿀 수 있습니다. 무시 패턴은 다른 값 외에도 null과 일치합니다.