nullable 참조 형식
null 허용 인식 불가능 컨텍스트에서는 모든 참조 형식이 null을 허용했습니다. null 허용 참조 형식은 코드로 인해 런타임에서 System.NullReferenceException이 throw될 가능성을 최소화하는 null 허용 인식 컨텍스트에서 사용하도록 설정된 기능 그룹을 나타냅니다. Nullable 참조 형식에는 참조 형식을 Nullable로 명시적으로 표시하는 기능을 포함하여 이러한 예외를 방지하는 데 도움이 되는 세 가지 기능이 포함되어 있습니다.
- 변수를 역참조하기 전에 변수가
null
일 수 있는지 여부를 확인하는 정적 흐름 분석이 향상되었습니다. - 흐름 분석에서 null-state를 확인하도록 API에 주석을 다는 특성입니다.
- 개발자가 변수에 대해 의도하는 null-state를 명시적으로 선언하는 데 사용하는 변수 주석입니다.
컴파일러는 컴파일 시간에 코드에 있는 모든 식의 null-state를 추적합니다. null-state에는 다음 세 가지 값 중 하나가 있습니다.
- not-null: 식이 not-
null
로 알려져 있습니다. - maybe-null: 식은
null
일 수 있습니다. - 인식 불가능: 컴파일러가 식의 null-state를 확인할 수 없습니다.
변수 주석은 참조 형식 변수의 Null 허용 여부를 결정합니다.
- null을 허용하지 않음: 변수에
null
값이나 maybe-null 식을 할당하면 컴파일러가 경고를 표시합니다. null을 허용하지 않는 변수의 기본 null-state는 not-null입니다. - null 허용: 변수에
null
값 또는 maybe-null 식을 할당할 수 있습니다. 변수의 null-state가 maybe-null인 경우 변수를 역참조하면 컴파일러는 경고를 표시합니다. 변수의 기본 null-state는 maybe-null입니다. - 인식 불가능: 변수에
null
값 또는 maybe-null 식을 할당할 수 있습니다. 변수를 역참조하거나 변수에 maybe-null 식을 할당할 때 컴파일러는 경고를 발급하지 않습니다.
인식 불가능 null-state 및 인식 불가능 null 허용 여부는 null 허용 참조 형식이 도입되기 전의 동작과 일치합니다. 이러한 값은 마이그레이션 중에 또는 앱이 null 허용 참조 형식을 사용하도록 설정하지 않은 라이브러리를 사용할 때 유용합니다.
null-state 분석 및 변수 주석은 기존 프로젝트에 대해 기본적으로 사용하지 않도록 설정됩니다. 이는 모든 참조 형식이 null을 계속 허용함을 의미합니다. .NET 6부터 새 프로젝트에 대해 기본적으로 활성화됩니다. Nullable 주석 컨텍스트를 선언하여 이러한 기능을 활성화하는 방법에 대한 자세한 내용은 Nullable 컨텍스트를 참조하세요.
이 문서의 나머지 부분에서는 코드가 null
값을 역참조할 수도 있는 경우 이 세 가지 기능 영역이 경고를 생성하는 방법을 설명합니다. 변수를 역참조하는 것은 다음 예와 같이 .
(점) 연산자를 사용하여 해당 멤버 중 하나에 액세스하는 것을 의미합니다.
string message = "Hello, World!";
int length = message.Length; // dereferencing "message"
값이 null
인 변수를 역참조하면 런타임에서 System.NullReferenceException을 throw합니다.
마찬가지로 개체가 다음과 같은 경우 개체의 멤버에 액세스하는 데 표기법을 사용할 때 []
경고가 생성될 수 있습니다 null
.
using System;
public class Collection<T>
{
private T[] array = new T[100];
public T this[int index]
{
get => array[index];
set => array[index] = value;
}
}
public static void Main()
{
Collection<int> c = default;
c[10] = 1; // CS8602: Possible derefence of null
}
학습 내용은 다음과 같습니다.
- 컴파일러의 null-state 분석: 컴파일러가 식이 not-null 또는 maybe-null인지 확인하는 방법입니다.
- 컴파일러의 null-state 분석을 위해 더 많은 컨텍스트를 제공하는 API에 적용되는 특성입니다.
- 변수 의도에 대한 정보를 제공하는 null 허용 변수 주석입니다. 주석은 필드가 멤버 메서드 시작 부분에 기본 null-state를 설정하는 데 유용합니다.
- 제네릭 형식 인수를 관리하는 규칙입니다. 형식 매개 변수가 참조 형식 또는 값 형식일 수 있으므로 새로운 제약 조건이 추가되었습니다.
?
접미사는 null 허용 값 형식과 null 허용 참조 형식에 대해 다르게 구현됩니다. - null 허용 컨텍스트는 대규모 프로젝트를 마이그레이션하는 데 도움이 됩니다. 마이그레이션할 때 앱의 일부에서 null 허용 컨텍스트 또는 경고를 사용하도록 설정할 수 있습니다. 추가 경고를 해결한 후 전체 프로젝트에 대해 null 허용 참조 형식을 사용하도록 설정할 수 있습니다.
마지막으로 struct
형식 및 배열의 null-state 분석에 대해 알려진 문제에 대해 알아봅니다.
C#의 null 허용 안전성에 대한 학습 모듈에서 이러한 개념을 살펴볼 수도 있습니다.
null-state 분석
null 허용 참조 형식이 사용하도록 설정되면 null-state 분석은 참조의 null-state를 추적합니다. 식은 not-null 또는 maybe-null입니다. 컴파일러는 다음 두 가지 방법으로 변수가 not-null임을 확인합니다.
- 변수에 not-null로 알려진 값이 할당되었습니다.
- 변수가
null
인지 검사되었으며 해당 검사 이후 수정되지 않음.
null 허용 참조 형식이 사용하도록 설정되지 않은 경우 모든 식은 인식 불가능의 null-state를 가집니다. 섹션의 나머지 부분에서는 null 허용 참조 형식이 사용하도록 설정된 경우의 동작을 설명합니다.
컴파일러에서 not-null로 확인되지 않은 변수는 maybe-null로 간주됩니다. 분석에서는 실수로 null
값을 역참조할 수 있는 상황에 대해 경고를 제공합니다. 컴파일러는 null-state를 기반으로 경고를 생성합니다.
- 변수가 not-null인 경우 해당 변수는 안전하게 역참조될 수 있습니다.
- 변수가 maybe-null인 경우 해당 변수를 역참조하기 전에 검사하여 변수가
null
이 아닌지 확인해야 합니다.
다음 예제를 참조하세요.
string message = null;
// warning: dereference null.
Console.WriteLine($"The length of the message is {message.Length}");
var originalMessage = message;
message = "Hello, World!";
// No warning. Analysis determined "message" is not-null.
Console.WriteLine($"The length of the message is {message.Length}");
// warning!
Console.WriteLine(originalMessage.Length);
앞의 예제에서 컴파일러는 첫 번째 메시지가 인쇄될 때 message
가 maybe-null임을 확인합니다. 두 번째 메시지에 대한 경고는 없습니다. 마지막 코드 줄은 originalMessage
가 null일 수 있으므로 경고를 생성합니다. 다음 예는 노드 트리를 루트로 트래버스하고 트래버스 중에 각 노드를 처리하는 더 실용적인 용도를 보여 줍니다.
void FindRoot(Node node, Action<Node> processNode)
{
for (var current = node; current != null; current = current.Parent)
{
processNode(current);
}
}
이전 코드는 current
변수를 역참조하기 위한 경고를 생성하지 않습니다. 정적 분석에서 current
가 maybe-null이면 이 변수를 역참조하지 않는 것으로 확인합니다. current.Parent
에 액세스하기 전과 current
를 ProcessNode
작업에 전달하기 전에 current
변수가 null
인지 검사됩니다. 이전 예제에서는 지역 변수가 초기화 또는 할당되거나 null
과 비교될 때 컴파일러가 해당 변수의 null-state를 확인하는 방법을 보여 줍니다.
null-state 분석은 호출된 메서드를 추적하지 않습니다. 결과적으로 모든 생성자가 호출하는 공통 도우미 메서드에서 초기화된 필드는 다음 템플릿을 사용하여 경고를 생성합니다.
null을 허용하지 않는 속성 'name'은 생성자를 종료할 때 non-null 값을 포함해야 합니다.
생성자 연결 또는 도우미 메서드의 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";
}
}
참고 항목
C# 10에는 한정된 할당 및 null-state 분석에 몇 가지 개선이 적용되었습니다. C# 10으로 업그레이드하면 가양성인 null 허용 경고가 줄어든 것을 알 수 있습니다. 한정된 할당 개선 기능 사양에서 개선 사항에 대해 자세히 알아보세요.
null 허용 상태 분석 및 컴파일러가 생성하는 경고는 null
을 역참조하여 프로그램 오류를 방지하는 데 도움이 됩니다. null 허용 경고 해결에 대한 문서에서는 코드에 표시될 가능성이 가장 높은 경고를 수정하는 기술을 제공합니다.
API 시그니처의 특성
null-state 분석에는 API의 의미 체계를 이해하기 위한 개발자의 힌트가 필요합니다. 일부 API는 null 검사를 제공하며 변수의 null-state를 maybe-null에서 not-null로 변경합니다. 다른 API는 입력 인수의 null-state에 따라 not-null 또는 maybe-null인 식을 반환합니다. 예를 들어, 메시지를 대문자로 표시하는 다음 코드를 살펴봅니다.
void PrintMessageUpper(string? message)
{
if (!IsNull(message))
{
Console.WriteLine($"{DateTime.Now}: {message.ToUpper()}");
}
}
bool IsNull(string? s) => s == null;
검사를 기반으로 개발자는 이 코드를 안전한 것으로 간주하며 코드가 경고를 생성해서는 안 됩니다. 그러나 컴파일러는 IsNull
이 null 검사를 제공하고 message
를 maybe-null 변수로 간주하여 message.ToUpper()
문에 대해 경고를 발급한다는 사실을 알지 못합니다. 이 경고를 수정하려면 NotNullWhen
특성을 사용합니다.
bool IsNull([NotNullWhen(false)] string? s) => s == null;
이 특성은 IsNull
이 false
를 반환하는 경우 매개 변수 s
가 null이 아님을 컴파일러에 알립니다. 컴파일러는 if (!IsNull(message)) {...}
블록 내에서 message
의 null-state를 not-null로 변경합니다. 경고가 발급되지 않습니다.
특성은 멤버를 호출하는 데 사용되는 개체 인스턴스의 인수, 반환 값, 멤버의null-state에 대해 자세한 정보를 제공합니다. 각 특성에 대한 자세한 내용은 null 허용 참조 특성에 대한 언어 참조 문서에서 찾을 수 있습니다. .NET 5부터는 모든 .NET 런타임 API에 주석이 추가됩니다. 인수 및 반환 값의 null-state에 대한 의미 체계 정보를 제공하도록 고유 API에 주석을 달아 정적 분석을 개선합니다.
null 허용 변수 주석
null-state 분석은 지역 변수에 대한 강력한 분석을 제공합니다. 멤버 변수에 대한 더 자세한 정보를 컴파일러에 제공해야 합니다. 멤버의 왼쪽 괄호에 있는 모든 필드의 null-state를 설정하려면 컴파일러에 추가 정보가 필요합니다. 액세스 가능한 생성자는 개체를 초기화하는 데 사용할 수 있습니다. 멤버 필드를 null
로 설정할 수 있는 경우 컴파일러는 각 메서드의 시작 부분에서 null-state가 maybe-null이라고 가정해야 합니다.
변수가 null 허용 참조 형식 또는 null을 허용하지 않는 참조 형식인지 선언할 수 있는 주석을 사용합니다. 이러한 주석은 변수의 null-state에 대한 중요한 문을 생성합니다.
- 참조는 null이 아니어야 합니다. null을 허용하지 않는 참조 변수의 기본 상태는 not-null입니다. 컴파일러는 null이 아닌지 먼저 확인하지 않고 이러한 참조를 역참조하기에 안전한지 확인하는 규칙을 적용합니다.
- 이 변수는 null이 아닌 값으로 초기화되어야 합니다.
- 이 변수에는
null
값을 절대로 할당할 수 없습니다. 코드가 null이면 안 되는 변수에 maybe-null 식을 할당하면 컴파일러가 경고를 발생시킵니다.
- 참조가 null일 수 있습니다. null 허용 참조 변수의 기본 상태는 maybe-null입니다. 컴파일러는
null
참조를 올바르게 확인하도록 규칙을 적용합니다.- 변수는 값이
null
이 아니라는 것을 컴파일러가 보장할 수 있는 경우에만 역참조될 수 있습니다. - 이러한 변수는 기본
null
값으로 초기화될 수 있으며 다른 코드에서는null
값이 할당될 수 있습니다. - 코드가 null일 수도 있는 변수에 maybe-null 식을 할당하면 컴파일러가 경고를 발생시키지 않습니다.
- 변수는 값이
모든 null을 허용하지 않는 참조 변수에는 기본 null-state인 not-null이 있습니다. null을 허용하는 모든 참조 변수에는 초기 null-state인 maybe-null이 있습니다.
nullable 참조 형식은 nullable 값 형식과 동일한 구문을 사용하여 작성합니다. 변수 형식에 ?
가 추가됩니다. 예를 들어 다음 변수 선언은 nullable 문자열 변수 name
을 나타냅니다.
string? name;
null 허용 참조 형식이 사용하도록 설정되면 형식 이름에 ?
이 추가되지 않은 모든 변수는 null을 허용하지 않는 참조 형식입니다. 이 기능을 사용하도록 설정하면 기존 코드의 모든 참조 형식 변수가 포함됩니다. 그러나 암시적 형식 지역 변수(var
을 사용하여 선언됨)는 null 허용 참조 형식입니다. 이전 섹션에서 살펴본 것처럼 정적 분석은 지역 변수의 null-state를 확인하여 역참조하기 전에 해당 변수가 maybe-null인지 확인합니다.
경우에 따라 변수가 null이 아님을 알고 있지만 컴파일러에서는 변수의 null-state가 maybe-null임을 판단하는 경우 경고를 재정의해야 합니다. 변수 이름 뒤에 null-forgiving 연산자인 !
를 사용하여 null-state를 not-null로 강제합니다. 예를 들어 name
변수가 null
이 아닌 것으로 알고 있는데 컴파일러 경고가 발생하는 경우 다음 코드를 작성하여 컴파일러 분석을 재정의할 수 있습니다.
name!.Length;
null 허용 참조 형식 및 null 허용 값 형식은 유사한 의미 체계 개념을 제공합니다. 즉, 변수는 값이나 개체를 나타낼 수 있거나 해당 변수가 null
일 수 있습니다. 그러나 null 허용 참조 형식과 null 허용 값 형식은 서로 다르게 구현됩니다. null 허용 값 형식은 System.Nullable<T>을 사용하여 구현되고, null 허용 참조 형식은 컴파일러에서 읽는 특성에 의해 구현됩니다. 예를 들어 string?
및 string
은 둘 다 동일한 형식(System.String)으로 표현됩니다. 그러나 int?
및 int
는 각각 System.Nullable<System.Int32>
및 System.Int32로 표현됩니다.
null 허용 참조 형식은 컴파일 시간 기능입니다. 즉, 호출자가 경고를 무시하고 의도적으로 null 허용이 아닌 참조를 기대하는 메서드에 대한 인수로 null
을 사용할 수 있음을 의미합니다. 라이브러리 작성자는 null 인수 값에 대한 런타임 검사를 포함해야 합니다. ArgumentNullException.ThrowIfNull은 런타임 시 null에 대해 매개 변수를 확인하는 데 기본 설정되는 옵션입니다.
Important
null 허용 주석을 사용하도록 설정하면 Entity Framework Core가 데이터 멤버가 필요한지 여부를 결정하는 방법이 변경될 수 있습니다. 자세한 내용은 Entity Framework Core Fundamentals: null 허용 참조 형식 작업 문서에서 알아볼 수 있습니다.
제네릭
제네릭에는 임의 형식 매개 변수 T
에 대한 T?
를 처리하는 자세한 규칙이 필요합니다. null 허용 값 형식과 null 허용 참조 형식의 기록과 서로 다른 구현으로 인해 규칙은 자세히 설명되어야 합니다. Null 허용 값 형식은 System.Nullable<T> 구조체를 사용하여 구현됩니다. Null 허용 참조 형식은 컴파일러에 의미 체계 규칙을 제공하는 형식 주석으로 구현됩니다.
T
의 형식 인수가 참조 형식인 경우T?
는 해당 null 허용 참조 형식을 참조합니다. 예를 들어,T
가string
이면T?
는string?
입니다.T
의 형식 인수가 값 형식이면T?
는 동일한 값 형식T
를 참조합니다. 예를 들어,T
가int
이면T?
도int
입니다.T
의 형식 인수가 null 허용 참조 형식인 경우T?
는 동일한 null 허용 참조 형식을 참조합니다. 예를 들어,T
가string?
이면T?
도string?
입니다.T
의 형식 인수가 null 허용 값 형식인 경우T?
는 동일한 null 허용 값 형식을 참조합니다. 예를 들어,T
가int?
이면T?
도int?
입니다.
반환 값의 경우 T?
는 [MaybeNull]T
에 해당하고, 인수 값의 경우 T?
는 [AllowNull]T
에 해당합니다. 자세한 내용은 언어 참조의 null-state 분석을 위한 특성 문서를 참조하세요.
제약 조건을 사용하여 다른 동작을 지정할 수 있습니다.
class
제약 조건은T
가 null을 허용하지 않는 참조 형식(예:string
)이어야 함을 의미합니다.T
에 대해string?
와 같은 null 허용 참조 형식을 사용하는 경우 컴파일러가 경고를 생성합니다.class?
제약 조건은T
가 null을 허용하지 않는 참조 형식(string
) 또는 null 허용 참조 형식(예:string?
)이어야 함을 의미합니다. 형식 매개 변수가string?
와 같은 null 허용 참조 형식인 경우T?
의 식은string?
와 같은 동일한 null 허용 참조 형식을 참조합니다.notnull
제약 조건은T
가 null을 허용하지 않는 참조 형식 또는 null을 허용하지 않는 값 형식이어야 함을 의미합니다. 형식 매개 변수에 null 허용 참조 형식 또는 null 허용 값 형식을 사용하는 경우 컴파일러가 경고를 생성합니다. 또한T
가 값 형식인 경우 반환 값은 해당 null 허용 값 형식이 아닌 이 값 형식입니다.
이러한 제약 조건은 T
가 사용되는 방식에 대한 자세한 정보를 컴파일러에 제공하는 데 도움이 됩니다. 이는 개발자가 T
의 형식을 선택할 때 도움이 되며 제네릭 형식의 인스턴스를 사용할 때 더 나은 null-state 분석을 제공합니다.
Nullable 컨텍스트
소규모 프로젝트의 경우 null 허용 참조 형식을 사용하도록 설정하고 경고를 수정한 후 계속할 수 있습니다. 그러나 대규모 프로젝트 및 다중 프로젝트 솔루션의 경우 많은 수의 경고가 발생할 수 있습니다. null 허용 참조 형식을 사용하기 시작할 때 pragma를 사용하여 파일별로 null 허용 참조 형식을 사용하도록 설정할 수 있습니다. System.NullReferenceException을 throw하는 것을 방지하는 새 기능은 기존 코드베이스에서 사용할 때 중단을 유발할 수 있습니다.
- 명시적 형식의 참조 변수는 모두 null을 허용하지 않는 참조 형식으로 해석됩니다.
- 제네릭의
class
제약 조건의 의미가 null을 허용하지 않는 참조 형식을 의미하도록 변경되었습니다. - 이러한 새 규칙으로 인해 새로운 경고가 생성됩니다.
null 허용 주석 컨텍스트가 컴파일러의 동작을 결정합니다. null 허용 주석 컨텍스트에는 4개의 값이 있습니다.
- disable: 코드가 null 허용 인식 불가능입니다. Disable은 새 구문이 오류 대신 경고를 생성한다는 점을 제외하면 null 허용 참조 형식이 사용하도록 설정되기 전의 동작과 일치합니다.
- null 허용 경고가 사용되지 않습니다.
- 모든 참조 형식 변수는 null 허용 참조 형식입니다.
?
접미사를 사용하여 null 허용 참조 형식을 선언하면 경고가 생성됩니다.- null forgiving 연산자인
!
를 사용할 수 있지만 영향은 없습니다.
- enable: 컴파일러는 모든 null 참조 분석과 모든 언어 기능을 사용하도록 설정합니다.
- 모든 새 null 허용 경고가 사용됩니다.
?
접미사를 사용하여 null 허용 참조 형식을 선언할 수 있습니다.?
접미사가 없는 참조 형식 변수는 null을 허용하지 않는 참조 형식입니다.- null 용서 연산자는 가능한 역참
null
조에 대한 경고를 표시하지 않습니다.
- warnings: 컴파일러가 모든 null 분석을 수행하고 코드가
null
을 역참조할 수 있는 경우 경고를 내보냅니다.- 모든 새 null 허용 경고가 사용됩니다.
?
접미사를 사용하여 null 허용 참조 형식을 선언하면 경고가 생성됩니다.- 모든 참조 형식 변수는 null일 수 있습니다. 그러나 멤버는
?
접미사로 선언되지 않은 경우 모든 메서드의 여는 괄호에 not-null의 null-state를 가집니다. - null forgiving 연산자인
!
를 사용할 수 있습니다.
- 주석: 코드가
null
을 역참조할 때 또는 null을 허용하지 않는 변수에 maybe-null 식을 할당할 때 컴파일러는 경고를 표시하지 않습니다.- 새로운 null 허용 경고가 모두 사용 안 함으로 설정됩니다.
?
접미사를 사용하여 null 허용 참조 형식을 선언할 수 있습니다.?
접미사가 없는 참조 형식 변수는 null을 허용하지 않는 참조 형식입니다.- null forgiving 연산자인
!
를 사용할 수 있지만 영향은 없습니다.
.csproj 파일에 <Nullable>
요소를 사용하여 프로젝트에 대한 nullable 주석 컨텍스트 및 nullable 경고 컨텍스트를 설정할 수 있습니다. 이 요소는 컴파일러가 형식의 null 허용 여부를 해석하는 방법 및 내보내는 경고를 구성합니다. 다음 표에서는 허용 가능한 값을 보여주고 지정한 컨텍스트를 요약합니다.
Context | Dereference 경고 | 할당 경고 | 참조 형식 | ? 접미사 |
! 연산자 |
---|---|---|---|---|---|
disable |
사용 안 함 | 사용 안 함 | 모두 null 허용입니다. | 경고 생성 | 아무런 영향이 없습니다. |
enable |
사용 | 사용 | ? 로 선언하지 않는 한 null을 허용하지 않음 |
nullable 형식 선언 | 가능한 null 할당에 대한 경고를 표시하지 않습니다. |
warnings |
설정됨 | 해당 없음 | 모두 null 허용이지만 메서드의 여는 중괄호에서 멤버는 not-null로 간주됩니다. | 경고 생성 | 가능한 null 할당에 대한 경고를 표시하지 않습니다. |
annotations |
사용 안 함 | 사용 안 함 | ? 로 선언하지 않는 한 null을 허용하지 않음 |
nullable 형식 선언 | 아무런 영향이 없습니다. |
disabled 컨텍스트에서 컴파일된 코드의 참조 형식 변수는 null 허용 인식 불가능입니다. null
리터럴이나 maybe-null 변수를 null 허용 인식 불가능인 변수에 할당할 수 있습니다. 그러나 nullable-oblivious 변수의 기본 상태는 not-null입니다.
프로젝트에 가장 적합한 설정을 선택할 수 있습니다.
- 진단이나 새로운 기능을 기반으로 업데이트하지 않으려는 레거시 프로젝트에 대해서는 사용 중지를 선택합니다.
- 코드에서 System.NullReferenceException이 throw될 수 있는 위치를 확인하려면 경고를 선택합니다. null을 허용하지 않는 참조 형식을 사용하도록 코드를 수정하기 전에 이러한 경고를 해결할 수 있습니다.
- 경고를 사용하기 전에 설계 의도를 표현하려면 annotations를 선택합니다.
- null 참조 예외로부터 보호하려는 새 프로젝트와 활성 프로젝트에 대해 사용을 선택합니다.
예제:
<Nullable>enable</Nullable>
또한 지시문을 사용하여 소스 코드의 아무 곳에나 이러한 동일한 컨텍스트를 설정할 수도 있습니다. 이러한 지시문은 대규모 코드베이스를 마이그레이션할 때 가장 유용합니다.
#nullable enable
: null 허용 주석 컨텍스트와 null 허용 경고 컨텍스트를 enable로 설정합니다.#nullable disable
: null 허용 주석 컨텍스트와 null 허용 경고 컨텍스트를 사용 중지로 설정합니다.#nullable restore
: null 허용 주석 컨텍스트와 null 허용 경고 컨텍스트를 프로젝트 설정으로 복원합니다.#nullable disable warnings
: null 허용 경고 컨텍스트를 disable로 설정합니다.#nullable enable warnings
: null 허용 경고 컨텍스트를 enable로 설정합니다.#nullable restore warnings
: null 허용 경고 컨텍스트를 프로젝트 설정으로 복원합니다.#nullable disable annotations
: null 허용 주석 컨텍스트를 disable로 설정합니다.#nullable enable annotations
: null 허용 주석 컨텍스트를 enable로 설정합니다.#nullable restore annotations
: nullable 주석 컨텍스트를 프로젝트 설정으로 복원합니다.
모든 코드 줄에 대해 다음 조합 중 원하는 것을 설정할 수 있습니다.
경고 컨텍스트 | 주석 컨텍스트 | 사용할 용어 |
---|---|---|
프로젝트 기본값 | 프로젝트 기본값 | 기본값 |
enable | disable | 분석 경고 수정 |
enable | 프로젝트 기본값 | 분석 경고 수정 |
프로젝트 기본값 | enable | 형식 주석 추가 |
enable | enable | 이미 마이그레이션된 코드 |
disable | enable | 경고를 수정하기 전에 코드에 주석 달기 |
disable | disable | 마이그레이션된 프로젝트에 레거시 코드 추가 |
프로젝트 기본값 | disable | 거의 없음 |
disable | 프로젝트 기본값 | 거의 없음 |
이러한 9가지 조합은 컴파일러가 코드에 대해 내보내는 진단에 대한 세분화된 제어를 제공합니다. 아직 해결할 준비가 되지 않은 추가 경고를 표시하지 않고도 업데이트 중인 모든 영역에서 더 많은 기능을 사용하도록 설정할 수 있습니다.
Important
전역 null 허용 컨텍스트는 생성된 코드 파일에 적용되지 않습니다. 두 전략에서 null 허용 컨텍스트는 생성됨으로 표시된 모든 소스 파일에 대해 disabled입니다. 즉, 생성된 파일의 API가 주석 처리되지 않습니다. 다음 네 가지 방법으로 파일은 생성됨으로 표시됩니다.
- .editorconfig에서 해당 파일에 적용되는 섹션에
generated_code = true
를 지정합니다. - 파일의 맨 위에 있는 주석에
<auto-generated>
또는<auto-generated/>
를 배치합니다. 해당 주석의 모든 줄에 넣을 수 있지만 주석 블록은 파일의 첫 번째 요소여야 합니다. - 파일 이름을 TemporaryGeneratedFile_로 시작합니다.
- 파일 이름을 .designer.cs, .generated.cs, .g.cs 또는 .g.i.cs로 종료합니다.
생성기는 #nullable
전처리기 지시문을 사용하여 옵트인할 수 있습니다.
기본 nullable 주석 및 경고 컨텍스트는 disabled입니다. 이는 기존 코드가 변경 없이 새로운 경고를 생성하지 않고 컴파일됨을 의미합니다. .NET 6부터 새 프로젝트에는 모든 프로젝트 템플릿에 <Nullable>enable</Nullable>
요소가 포함됩니다.
이러한 옵션은 null 허용 참조 형식을 사용하도록 기존 코드베이스를 업데이트하는 두 가지 고유한 전략을 제공합니다.
알려진 문제
참조 형식을 포함하는 배열 및 구조체는 null 허용 참조뿐만 아니라 null 안전을 확인하는 정적 분석에서도 알려진 함정입니다. 두 경우 모두 null을 허용하지 않는 참조 형식이 경고를 생성하지 않고 null
로 초기화될 수 있습니다.
구조체
null을 허용하지 않는 참조 형식을 포함하는 구조에서는 경고 없이 default
를 할당할 수 있습니다. 다음 예제를 참조하세요.
using System;
#nullable enable
public struct Student
{
public string FirstName;
public string? MiddleName;
public string LastName;
}
public static class Program
{
public static void PrintStudent(Student student)
{
Console.WriteLine($"First name: {student.FirstName.ToUpper()}");
Console.WriteLine($"Middle name: {student.MiddleName?.ToUpper()}");
Console.WriteLine($"Last name: {student.LastName.ToUpper()}");
}
public static void Main() => PrintStudent(default);
}
앞의 예제에서 null을 허용하지 않는 참조 형식 FirstName
및 LastName
이 null인 동안 PrintStudent(default)
에는 경고가 없습니다.
또 다른 일반적인 사례는 일반 구조체를 처리하는 경우입니다. 다음 예제를 참조하세요.
#nullable enable
public struct S<T>
{
public T Prop { get; set; }
}
public static class Program
{
public static void Main()
{
string s = default(S<string>).Prop;
}
}
앞의 예에서 Prop
속성은 런타임에 null
입니다. 경고 없이 null을 허용하지 않는 문자열에 할당됩니다.
배열
배열은 nullable 참조 형식의 알려진 문제가 되기도 합니다. 경고를 생성하지 않는 다음 예제를 고려하세요.
using System;
#nullable enable
public static class Program
{
public static void Main()
{
string[] values = new string[10];
string s = values[0];
Console.WriteLine(s.ToUpper());
}
}
앞의 예제에서 배열 선언은 해당 요소가 모두 null
로 초기화되는 동안 null을 허용하지 않는 문자열을 보유함을 나타냅니다. 그런 다음, s
변수에는 null
값(배열의 첫 번째 요소)이 할당됩니다. 마지막으로 s
변수가 역참조되어 런타임 예외가 발생합니다.
참고 항목
.NET