Quick Reference
null conditional은 null receiver에서 member/indexer access를 멈추고 null을 만들며, null coalescing은 null일 때만 fallback을 evaluate합니다. 이 연산자들은 null만 다루며 range, format, validation, thread safety까지 해결하지 않습니다.
string displayName = user?.Profile?.Nickname ?? "Guest";
char? first = text?[0];
cache ??= new Dictionary<string, string>();
OnChanged?.Invoke(this, EventArgs.Empty);?.는 member/method access,?[]는 indexer/array access에 씁니다.??는 left가 null일 때만 right를 evaluate하고 right-associative입니다.??=는 assignable variable/property/indexer가 null일 때만 대입합니다.?[]는 null collection만 막습니다. index out of range는 그대로 발생합니다.
Conditional access와 평가 중단
int? count = orders?.Count;
string? nickname = user?.Profile?.Nickname;
int? first = numbers?[0];user?.Profile?.Nickname은 user 또는 Profile이 null이면 뒤 member access를 evaluate하지 않습니다. 그러나 parentheses로 chain을 끊으면 null propagation이 이어지지 않을 수 있습니다.
// (user?.Profile).Nickname; // Profile 결과가 null이면 Nickname access에서 실패 가능null conditional은 receiver null만 처리합니다. receiver가 non-null인데 getter가 throw하거나 index가 범위를 넘거나 method가 failure를 반환하는 경우에는 해당 결과를 처리해야 합니다.
int? first = numbers?[0]; // numbers가 non-null이고 비어 있으면 IndexOutOfRangeExceptionFallback과 conditional assignment
string label = primary ?? secondary ?? "fallback";
Dictionary<string, string>? cache = null;
cache ??= new Dictionary<string, string>();??와 ??=는 right-associative이며 right-hand side는 필요할 때만 evaluate합니다. empty string, 0, false, empty collection은 null이 아니므로 fallback되지 않습니다. blank text까지 바꿀지 여부는 string.IsNullOrWhiteSpace 같은 별도 domain rule로 표현합니다.
??=는 lazy initialization처럼 보이지만 multiple thread가 동시에 null을 보면 factory를 여러 번 호출하거나 마지막 assignment가 이기는 race가 생길 수 있습니다. shared state에는 Lazy<T>, lock, Interlocked.CompareExchange, concurrency collection처럼 ownership에 맞는 synchronization을 사용합니다.
NRT와 API contract
public static string Normalize(string? raw)
{
return raw?.Trim() ?? "";
}위 method는 null을 empty string으로 정책적으로 변환합니다. null이 "missing", empty string이 "provided but blank"라면 이 conversion은 정보를 잃으므로 caller에 nullable return을 남기거나 Result type을 사용합니다.
! null-forgiving operator는 ?./??와 다릅니다. !는 compiler warning을 억제할 뿐 evaluation이나 runtime null 값을 바꾸지 않습니다. annotation·flow analysis·public boundary guard는 nullable reference type에서 확인합니다.
자주 틀리는 부분
??를 입력 정규화 도구처럼 쓰면 null과 empty/invalid 상태를 섞게 됩니다. fallback이 user-visible default인지, missing configuration error인지, optional dependency인지 먼저 정하세요.
?.Invoke는 event handler를 async하게 기다리거나 handler exception을 격리하지 않습니다. event lifecycle과 failure policy는 delegate와 event에서 다룹니다.
참고 링크
2 sources