주석: ?, !, MaybeNull과 NotNull
nullable 형식에는 ?, null 용서에는 !를 사용하고 정확한 흐름 분석에는 MaybeNull 및 NotNullWhen 같은 특성을 사용합니다.
주석: ?, !, MaybeNull과 NotNull은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
?와 !를 넘어서: Nullability 특성
기본적인 ? 주석과 null 확인만으로 대부분의 경우를 처리할 수 있지만, 일부 패턴에는 더 표현력이 높은 주석이 필요합니다. System.Diagnostics.CodeAnalysis 네임스페이스는 컴파일러가 null 흐름을 더 깊이 이해하도록 돕는 특성을 제공합니다.
MaybeNull과 NotNull
[MaybeNull]은 null 비허용 반환 형식이 실제로는 null일 수 있음을 컴파일러에 알립니다(예: 제네릭 메서드). [NotNull]은 호출 후 null 허용 매개 변수가 null이 아님을 보장합니다.
using System.Diagnostics.CodeAnalysis;
// [MaybeNull]: return might be null even though T is non-nullable
[return: MaybeNull]
public T Find<T>(int id)
{
// Returns default(T) which is null for reference types
return _cache.TryGetValue(id, out var val) ? val : default!;
}
// [NotNull]: after this call, output is guaranteed non-null
public static void EnsureNotNull<T>(
[NotNull] ref T? value,
T defaultValue) where T : class
{
value ??= defaultValue;
}NotNullWhen: 조건부 null 비허용
[NotNullWhen(true)]은 메서드가 true를 반환할 때 출력 매개 변수가 null이 아님을 컴파일러에 알립니다. 표준 TryParse 패턴에 이 방식의 주석이 사용됩니다.
using System.Diagnostics.CodeAnalysis;
public static bool TryParseEmail(
string? input,
[NotNullWhen(true)] out string? email)
{
if (input?.Contains('@') == true)
{
email = input.Trim().ToLower();
return true;
}
email = null;
return false;
}
// Usage — no warning after true check:
if (TryParseEmail(raw, out var email))
Console.WriteLine(email.Length); // safe — email is non-null hereMaybeNullWhen: 조건부 null 허용
[MaybeNullWhen(false)]은 그 반대의 의미로, 메서드가 false를 반환할 때 출력 값이 null일 수 있음을 나타냅니다. 사전의 TryGetValue 패턴에 사용됩니다.
// This is how Dictionary<K,V>.TryGetValue is annotated:
public bool TryGetValue(
TKey key,
[MaybeNullWhen(false)] out TValue value)
{ ... }
// Usage:
if (!dict.TryGetValue("key", out var value))
return; // early return — value is null in this branch
Console.WriteLine(value.Length); // safe after the guardAllowNull과 DisallowNull
null 비허용 속성에 [AllowNull]을 지정하면 호출자가 해당 속성에 null을 전달할 수 있습니다(예: null을 빈 문자열로 변환하는 설정자). [DisallowNull]은 null 허용 형식에 null을 전달하지 못하도록 합니다.
public class Config
{
private string _name = "";
// Allow setting null (setter converts null -> empty)
[AllowNull]
public string Name
{
get => _name;
set => _name = value ?? "";
}
// Getter always returns non-null: fine
// Setter accepts null: [AllowNull] tells compiler that's OK
}NotNullIfNotNull: null 허용성 전파
[NotNullIfNotNull(paramName)]은 매개 변수 X가 null이 아니면 반환 값도 null이 아님을 의미합니다. 변환 함수에 유용합니다.
[return: NotNullIfNotNull(nameof(value))]
public static string? Normalize(string? value)
{
return value?.Trim().ToLower();
}
// Usage:
string name = " Alice ";
string norm1 = Normalize(name)!; // guaranteed non-null
string? raw = GetRaw();
string? norm2 = Normalize(raw); // still nullable (raw might be null)DoesNotReturn
[DoesNotReturn]은 항상 예외를 발생시키는 메서드를 표시합니다. 컴파일러는 호출 뒤의 코드에 도달할 수 없음을 알고 불필요한 null 경고를 억제합니다.
using System.Diagnostics.CodeAnalysis;
[DoesNotReturn]
public static void ThrowNotFound(int id)
=> throw new KeyNotFoundException($"Entity {id} not found");
// Usage — no null warning after the call:
var order = _db.Orders.Find(id);
if (order is null) ThrowNotFound(id);
Console.WriteLine(order.Id); // no CS8602 — compiler knows ThrowNotFound threwMemberNotNull: 필드에 대한 사후 조건
[MemberNotNull]은 메서드가 반환된 후 특정 필드가 null이 아님을 보장한다고 컴파일러에 알립니다. 지연 초기화 도우미에 유용합니다.
public class DataLoader
{
private string? _data;
[MemberNotNull(nameof(_data))]
private void EnsureLoaded()
{
if (_data is null)
_data = LoadFromFile();
}
public string GetData()
{
EnsureLoaded();
return _data; // no CS8603 — compiler knows _data is set
}
}주석 조합하기
정확한 API 계약을 위해 특성을 조합할 수 있습니다. 다음은 여러 특성을 조합한 연속 호출형 검사 도우미입니다.
public static class Guard
{
[return: NotNull]
public static T NotNull<T>(
[NotNull][AllowNull] T? value,
[CallerArgumentExpression(nameof(value))] string? name = null)
where T : class
{
ArgumentNullException.ThrowIfNull(value, name);
return value;
}
}
// Usage:
var product = Guard.NotNull(await _repo.FindAsync(id));
Console.WriteLine(product.Name); // no warningnull 연산자: ?. ?? ??=
null 조건부 연산자(?.), null 병합 연산자(??), null 병합 할당 연산자(??=)를 사용하면 장황한 if 확인 없이 간결하고 null에 안전한 코드를 작성할 수 있습니다.
string? name = GetName();
// ?. safe navigation
int? len = name?.Length;
string? upper = name?.ToUpper().Trim();
// ?? default value
string display = name ?? "Anonymous";
// ??= lazy init
name ??= "Default";
// Chaining
string result = user?.Profile?.DisplayName ?? user?.Name ?? "Guest";빠른 확인
out 매개 변수에 [NotNullWhen(true)]를 지정하면 컴파일러에 무엇을 알립니까?
복습: Nullability 주석
핵심 요점:
[NotNullWhen(true)]: TryParse 패턴으로, true를 반환하면 null이 아님[MaybeNull]: null 비허용 형식도 null을 반환할 수 있음(제네릭 기본값)[DoesNotReturn]: 메서드가 항상 예외를 발생시키므로 뒤의 코드는 실행되지 않음[MemberNotNull]: 메서드가 반환된 후 필드가 설정되어 있음을 보장?.,??,??=: 간결하고 null에 안전한 탐색 및 기본값 처리
자주 묻는 질문
“주석: ?, !, MaybeNull과 NotNull” 강의는 무료인가요?
네 — “주석: ?, !, MaybeNull과 NotNull” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“주석: ?, !, MaybeNull과 NotNull”에서 뭘 배우나요?
nullable 형식에는 ?, null 용서에는 !를 사용하고 정확한 흐름 분석에는 MaybeNull 및 NotNullWhen 같은 특성을 사용합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
C# Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“주석: ?, !, MaybeNull과 NotNull” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- NRT 활성화와 이해
- 주석: ?, !, MaybeNull과 NotNull
- null 조건부 및 null 병합 연산자
- 코드베이스를 NRT로 마이그레이션하기