Nullable 경고 해결

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

  • CS8597 - throw된 값은 null일 수 있습니다.
  • CS8600 - null 리터럴 또는 가능한 null 값을 null을 허용하지 않는 형식으로 변환합니다.
  • CS8601 - 가능한 null 참조 할당입니다.
  • CS8602 - 가능한 null 참조의 역참조.
  • CS8603 - 가능한 null 참조 반환입니다.
  • CS8604 - 매개 변수에 대한 가능한 null 참조 인수입니다.
  • CS8605 - 가능한 null 값을 unboxing합니다.
  • 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 허용 여부 특성 때문일 수 있음).
  • CS8624 - 참조 형식의 Null 허용 여부가 다르기 때문에 인수를 출력으로 사용할 수 없습니다.
  • CS8625 - null 리터럴을 null을 허용하지 않는 참조 형식으로 변환할 수 없습니다.
  • CS8629 - Null 허용 값 형식은 null일 수 있습니다.
  • CS8631 - 제네릭 형식 또는 메서드에서 형식을 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 제약 조건 형식과 일치하지 않습니다.
  • CS8633 - 메서드 형식 매개 변수 제약 조건의 Null 허용 여부가 인터페이스 메서드 형식 매개 변수 제약 조건과 일치하지 않습니다. 명시적 인터페이스 구현을 대신 사용하세요.
  • CS8634 - 이 형식은 제네릭 형식 또는 메서드에서 형식 매개 변수로 사용할 수 없습니다. 형식 인수의 Null 허용 여부가 '클래스' 제약 조건과 일치하지 않습니다.
  • 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' 절이 있는 패턴은 이 값과 성공적으로 일치할 수 있습니다.

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

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

  • 필요한 null 검사를 추가합니다.
  • ? 또는 ! null 허용 주석을 추가합니다.
  • Null 의미 체계를 설명하는 특성을 추가합니다.
  • 변수를 올바르게 초기화하는 중입니다.

가능한 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-statenot-null이어야 한다는 것을 알 수 있습니다. 컴파일러에게 이러한 팩트를 알려 주어야 합니다. 한 가지 방법은 널 허용 연산자인 !을 사용하는 것입니다. 다음 코드와 일치하도록 WriteLine 문을 변경할 수 있습니다.

Console.WriteLine(message!.Length);

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

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

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

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

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

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

null을 허용하지 않는 참조에 할당된 가능한 null

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

  • CS8597 - throw된 값은 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으로 변경됩니다. 컴파일러의 정적 분석에서는 maybe-null인 변수를 역참조하는 인스턴스를 찾을 수 있습니다.

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

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

이전 예에서는 메서드의 반환 값 할당을 보여 줍니다. 메서드가 not-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;
}

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

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

기존 코드에서는 해당 멤버의 null 의미 체계에 대해 컴파일러에 알리기 위해 다른 변경이 필요할 수 있습니다. 여러 생성자를 만들었을 수 있으며 클래스에 하나 이상의 멤버를 초기화하는 전용 도우미 메서드가 있을 수 있습니다. 초기화 코드를 단일 생성자로 이동하고 모든 생성자가 공통 초기화 코드를 사용하여 해당 생성자를 호출하도록 할 수 있습니다. 또는 System.Diagnostics.CodeAnalysis.MemberNotNullAttributeSystem.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute 특성을 사용할 수 있습니다. 이러한 특성은 메서드가 호출된 후 멤버가 not-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 의미 체계에 대해 컴파일러에 알리는 방법을 설명했습니다. 코드가 해당 특성의 약속을 준수하지 않으면 컴파일러는 경고합니다.

  • 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 및 기타 모든 값과 일치합니다.