nullable 참조 형식(C# 참조)

참고 항목

이 문서에서는 nullable 참조 형식을 설명합니다. nullable 값 형식을 선언할 수도 있습니다.

Null 허용 참조 형식은 null 허용 인식 컨텍스트에 옵트인된 코드에서 사용할 수 있습니다. nullable 참조 형식, null 정적 분석 경고 및 null 허용 연산자는 선택적 언어 기능입니다. 모두 기본적으로 꺼져 있습니다. ‘nullable 컨텍스트’는 빌드 설정을 사용하여 프로젝트 수준에서 제어되거나 pragma를 사용하여 빌드 설정에서 제어됩니다.

Important

.NET 6(C# 10)로 시작하는 모든 프로젝트 템플릿은 프로젝트에 대해 null 허용 컨텍스트를 사용하도록 설정합니다. 이전 템플릿으로 만든 프로젝트에는 이 요소가 포함되지 않으며, 프로젝트 파일에서 사용하도록 설정하거나 pragma를 사용하지 않는 한 이러한 기능은 해제됩니다.

nullable 인식 컨텍스트에서:

  • 참조 형식 T의 변수는 null이 아닌 값으로 초기화되어야 하며, null일 수 있는 값이 할당되지 않을 수 있습니다.
  • 참조 형식 T?의 변수는 null로 초기화되거나 null이 할당될 수 있지만, 역참조하기 전에 null에 대해 확인되어야 합니다.
  • m!의 경우와 같이 null 허용 연산자를 적용하면 T? 형식의 m 변수는 null이 아닌 것으로 간주합니다.

null을 허용하지 않는 참조 형식과 T nullable 참조 형식 T? 간 차이점은 컴파일러의 이전 규칙 해석에 따라 적용됩니다. T 형식의 변수 및 T? 형식의 변수는 동일한 .NET 형식으로 나타냅니다. 다음 예제에서는 null을 허용하지 않는 문자열 및 nullable 문자열을 선언하고 null 허용 연산자를 사용하여 null을 허용하지 않는 문자열에 값을 할당합니다.

string notNull = "Hello";
string? nullable = default;
notNull = nullable!; // null forgiveness

notNullnullable 변수는 둘 다 String 형식으로 나타냅니다. null을 허용하지 않는 형식 및 nullable 형식은 둘 다 같은 형식으로 저장되므로 nullable 참조 형식을 사용할 수 있는 여러 위치가 있습니다. 일반적으로 nullable 참조 형식은 기본 클래스 또는 구현된 인터페이스로 사용할 수 없습니다. nullable 참조 형식은 개체 생성 또는 형식 테스트 식에 사용할 수 없습니다. nullable 참조 형식은 멤버 액세스 식의 형식일 수 없습니다. 다음 예제에서는 다음 구문을 보여 줍니다.

public MyClass : System.Object? // not allowed
{
}

var nullEmpty = System.String?.Empty; // Not allowed
var maybeObject = new object?(); // Not allowed
try
{
    if (thing is string? nullableString) // not allowed
        Console.WriteLine(nullableString);
} catch (Exception? e) // Not Allowed
{
    Console.WriteLine("error");
}

nullable 참조 및 정적 분석

이전 섹션의 예제에서는 nullable 참조 형식의 특성을 보여 줍니다. nullable 참조 형식은 새 클래스 형식이 아니라 기존 참조 형식의 주석입니다. 컴파일러는 해당 주석을 사용하여 코드에서 잠재적 null 참조 오류를 찾을 수 있습니다. null을 허용하지 않는 참조 형식과 nullable 참조 형식 간에는 런타임 차이가 없습니다. 컴파일러는 null을 허용하지 않는 참조 형식에 대한 런타임 검사를 추가하지 않습니다. 컴파일 시간 분석에는 이점이 있습니다. 컴파일러는 코드에서 잠재적 null 오류를 찾고 해결하는 데 도움이 되는 경고를 생성합니다. 의도를 선언하고 코드가 해당 의도를 위반하면 컴파일러가 경고를 표시합니다.

nullable 사용 컨텍스트에서 컴파일러는 nullable 참조 형식 및 null을 허용하지 않는 참조 형식의 변수에서 정적 분석을 수행합니다. 컴파일러는 각 참조 변수의 null-statenot-null 또는 maybe-null로 추적합니다. null을 허용하지 않는 참조의 기본 상태는 not-null입니다. null 허용 참조의 기본 상태는 maybe-null입니다.

null을 허용하지 않는 참조 형식은 해당 null-statenot-null이므로 항상 안전하게 역참조해야 합니다. 해당 규칙을 적용하기 위해 null을 허용하지 않는 참조 형식이 null이 아닌 값으로 초기화되지 않는 경우 컴파일러는 경고를 실행합니다. 지역 변수는 선언된 위치에 할당되어야 합니다. 모든 필드에는 필드 이니셜라이저 또는 모든 생성자에 not-null 값이 할당되어야 합니다. 상태가 maybe-null인 참조에 null을 허용하지 않는 참조가 할당되는 경우 컴파일러가 경고를 실행합니다. 일반적으로 null을 허용하지 않는 참조는 not-null이므로 해당 변수가 역참조될 때 경고가 실행되지 않습니다.

참고 항목

null을 허용하지 않는 참조 형식에 maybe-null 식을 할당하면 컴파일러가 경고를 생성합니다. 그런 다음, 컴파일러는 not-null 식에 할당될 때까지 해당 변수에 대한 경고를 생성합니다.

nullable 참조 형식은 null에 초기화되거나 할당될 수 있습니다. 따라서 정적 분석에서는 역참조되기 전에 변수가 not-null인지 확인해야 합니다. null 허용 참조가 maybe-null로 확인되는 경우 null을 허용하지 않는 참조 변수에 할당하면 컴파일러 경고가 생성됩니다. 다음 클래스는 해당 경고의 예를 보여 줍니다.

public class ProductDescription
{
    private string shortDescription;
    private string? detailedDescription;

    public ProductDescription() // Warning! shortDescription not initialized.
    {
    }

    public ProductDescription(string productDescription) =>
        this.shortDescription = productDescription;

    public void SetDescriptions(string productDescription, string? details=null)
    {
        shortDescription = productDescription;
        detailedDescription = details;
    }

    public string GetDescription()
    {
        if (detailedDescription.Length == 0) // Warning! dereference possible null
        {
            return shortDescription;
        }
        else
        {
            return $"{shortDescription}\n{detailedDescription}";
        }
    }

    public string FullDescription()
    {
        if (detailedDescription == null)
        {
            return shortDescription;
        }
        else if (detailedDescription.Length > 0) // OK, detailedDescription can't be null.
        {
            return $"{shortDescription}\n{detailedDescription}";
        }
        return shortDescription;
    }
}

다음 코드 조각은 이 클래스를 사용하는 경우 컴파일러가 경고를 내보내는 위치를 보여 줍니다.

string shortDescription = default; // Warning! non-nullable set to null;
var product = new ProductDescription(shortDescription); // Warning! static analysis knows shortDescription maybe null.

string description = "widget";
var item = new ProductDescription(description);

item.SetDescriptions(description, "These widgets will do everything.");

앞의 예제에서는 참조 변수의 null-state를 확인하는 컴파일러의 정적 분석을 보여 줍니다. 컴파일러는 null 검사 및 할당에 대한 언어 규칙을 적용하여 분석에 대해 알립니다. 컴파일러는 메서드 또는 속성의 의미 체계를 가정할 수 없습니다. Null 검사를 수행하는 메서드를 호출하는 경우 컴파일러는 해당 메서드가 변수의 null-state에 영향을 준다는 것을 알 수 없습니다. 컴파일러에 인수 및 반환 값의 의미 체계를 알리는 특성을 API에 추가할 수 있습니다. 해당 특성은 .NET Core 라이브러리의 여러 일반적인 API에 적용되었습니다. 예를 들어 IsNullOrEmpty가 업데이트되었으며 컴파일러는 해당 메서드를 null 검사로 올바르게 해석합니다. null-state 정적 분석에 적용되는 특성에 관한 자세한 내용은 null 허용 특성 문서를 참조하세요.

nullable 컨텍스트 설정

두 가지 방법으로 nullable 컨텍스트를 제어할 수 있습니다. 프로젝트 수준에서 <Nullable>enable</Nullable> 프로젝트 설정을 추가할 수 있습니다. 단일 C# 소스 파일에서 #nullable enable pragma를 추가하여 nullable 컨텍스트를 사용하도록 설정할 수 있습니다. nullable 전략 설정 문서를 참조하세요. .NET 6 이전에는 새 프로젝트에서 기본값인 <Nullable>disable</Nullable>를 사용합니다. .NET 6부터 새 프로젝트에는 프로젝트 파일에 <Nullable>enable</Nullable> 요소가 포함됩니다.

C# 언어 사양

자세한 내용은 C# 언어 사양의 다음 제안을 참조하세요.

참고 항목