[PART4.제어문: 분기와 반복(6/13)] 속성 패턴 — 객체의 프로퍼티 값으로 분기 (C# 8) · 확장 속성 패턴 (C# 10)
객체의 여러 프로퍼티를 중괄호 안에서 동시에 매칭 / 관계·논리 패턴과 자유롭게 조합 / C# 10 점 표기법으로 중첩 객체를 평탄하게 검사
목차
1. [문제 제기] — 또 그놈의 null 체크와 && 사슬
Unity에서 RPG 인벤토리 시스템을 만든다고 가정합시다. "장착 가능한 무기 중 내구도가 남아 있고, 아직 장비되지 않은 아이템"을 골라야 합니다. 일반적으로는 이렇게 씁니다.
// 흔히 보는 분기 — null 체크 + && 사슬
if (item != null
&& item.ItemType == ItemType.Weapon
&& item.Durability > 0
&& item.IsEquipped == false)
{
EquipWeapon(item);
}
조건이 네 개인데도 벌써 시야가 어수선합니다. 만약 "한국에 사는 VIP 고객의 주문"처럼 객체가 한 단계 더 깊어지면 어떻게 될까요?
// 중첩 객체 검사 — null 체크가 폭발적으로 늘어남
if (order != null
&& order.Customer != null
&& order.Customer.Address != null
&& order.Customer.Address.Country == "KR"
&& order.Status == "Paid"
&& order.Amount > 0)
{
Ship(order);
}
문제는 두 가지입니다.
- 노이즈: 진짜 비즈니스 규칙(
Country == "KR",Amount > 0)이null체크에 파묻혀 보이지 않습니다. - 실수 유발:
Customer != null한 줄을 빠뜨리면 운영 환경에서NullReferenceException이 터집니다.
C# 8부터 도입된 속성 패턴(Property Pattern) 은 이 두 문제를 한 번에 해결합니다. 객체 안의 여러 프로퍼티를 중괄호 {} 안에서 동시에 검사하고, 중간 객체가 null이면 자동으로 false로 단락(short-circuit)됩니다. C# 10에서는 한 발 더 나아가 점(.) 표기법으로 중첩 객체까지 평탄하게 매칭할 수 있습니다.
이전 두 주제에서 is 타입 패턴(객체의 타입으로 분기)과 리스트 패턴(컬렉션의 모양으로 분기)을 다뤘습니다. 속성 패턴은 같은 패턴 매칭 가족의 세 번째 멤버 — 객체의 프로퍼티 값으로 분기합니다.
2. [개념 정의] — 객체 안을 들여다보는 한 줄 검사
2.1 비유: 면접 체크리스트
지원자의 이력서를 보고 "3년 차 이상이고 C# 경험이 있고 서울 거주"인 사람만 1차 통과시킨다고 합시다. 보통은 항목별로 따로따로 확인하지만, 속성 패턴은 체크리스트 한 장으로 동시에 검사하는 방식입니다.

2.2 기본 문법
is { ... }— 속성 패턴 (Property Pattern)is뒤에 중괄호로 감싼 프로퍼티 검사 목록을 적으면, 객체가null이 아니면서 모든 프로퍼티가 지정한 값과 일치할 때true가 된다. 형식은{ 프로퍼티이름: 패턴, ... }이다.
예시:if (order is { Status: "Paid", Amount: > 0 }) Ship(order);order가 null이 아니고, Status가 "Paid"이고, Amount가 0보다 크면 배송한다.
// Unity에서 흔한 데이터 클래스
public class Order
{
public string Status { get; init; } = "";
public decimal Amount { get; init; }
}
void ProcessOrder(Order order)
{
// 한 줄로 null 체크 + 두 프로퍼티 동시 검사
if (order is { Status: "Paid", Amount: > 0 })
{
Ship(order);
}
}
콜론 뒤에 오는 부분은 또 다른 패턴입니다. "Paid" 처럼 상수 패턴, > 0 처럼 관계 패턴, not null 처럼 논리 패턴 등 무엇이든 들어갈 수 있습니다. 속성 패턴이 강력한 이유가 바로 이 합성 가능성에 있습니다.
2.3 IL로 확인하기 — 정말 && 사슬과 같을까?
public static bool SimpleMatch(Order order)
=> order is { Status: "Paid", Amount: > 0 };
.method public hidebysig static bool SimpleMatch(class Order order) cil managed
{
// Code size: 40 (0x28)
IL_0000: ldarg.0
IL_0001: brfalse.s IL_0026 // order가 null이면 false 분기
IL_0003: ldarg.0
IL_0004: callvirt instance string Order::get_Status() // Status getter 호출
IL_0009: ldstr "Paid"
IL_000e: call bool [System.Runtime]System.String::op_Equality(string, string)
IL_0013: brfalse.s IL_0026 // Status가 "Paid"가 아니면 false 분기
IL_0015: ldarg.0
IL_0016: callvirt instance valuetype Decimal Order::get_Amount() // Amount getter
IL_001b: ldsfld valuetype Decimal Decimal::Zero
IL_0020: call bool Decimal::op_GreaterThan(Decimal, Decimal)
IL_0025: ret // 결과 그대로 반환
IL_0026: ldc.i4.0 // false
IL_0027: ret
}
핵심만 봅니다.
IL_0001: brfalse.s IL_0026—order가null이면 곧장false자리로 점프. 우리가null체크를 쓰지 않았는데 컴파일러가 알아서 끼워 넣었습니다.callvirt get_Status()+ 비교 +brfalse— 한 프로퍼티당 "getter 호출 → 비교 → 실패면 즉시 점프" 사슬이 반복됩니다.- 최종적으로 직접 손으로 쓴
o != null && o.Status == "Paid" && o.Amount > 0과 거의 동일한 IL이 생성됩니다.
다시 말해, 속성 패턴은 공짜 추상화입니다. 가독성은 올라가지만 런타임 비용은 늘지 않습니다.
3. [내부 동작] — 점 표기법은 어떻게 평탄해지는가
C# 10에서 추가된 확장 속성 패턴(Extended Property Pattern) 은 점 표기법으로 중첩 객체를 평탄하게 매칭합니다.
{ A.B.C: 패턴 }— 확장 속성 패턴 (Extended Property Pattern, C# 10) 중괄호 안에서 점(.) 표기법으로 중첩 프로퍼티 체인을 그대로 적을 수 있다. 중간 객체가 null이면 패턴은 NRE 대신 false가 된다.
예시:if (order is { Customer.Address.Country: "KR" }) ShipDomestic(order);Customer 또는 Address가 null이어도 NRE 없이 false로 처리된다.
3.1 두 표현은 의미가 같다

C# 8 표현과 C# 10 표현은 컴파일러 입장에서 완벽히 동일합니다. 같은 IL이 나옵니다. 직접 검증해 봅시다.
public record Address(string Country, string City);
public record Customer(string Name, Address Address);
public record Order(string Status, decimal Amount, Customer Customer);
public static bool NestedMatch(Order order) // C# 8 스타일
=> order is { Customer: { Address: { Country: "KR" } } };
public static bool DottedMatch(Order order) // C# 10 스타일
=> order is { Customer.Address.Country: "KR" };
두 메서드의 IL을 나란히 디컴파일한 결과는 다음과 같습니다.
.method public hidebysig static bool NestedMatch(class Order order) cil managed
{
// Code size: 42 (0x2a)
.locals init ([0] class Customer, [1] class Address)
IL_0000: ldarg.0
IL_0001: brfalse.s IL_0028 // order == null → false
IL_0003: ldarg.0
IL_0004: callvirt instance class Customer Order::get_Customer()
IL_0009: stloc.0 // Customer 캐싱
IL_000a: ldloc.0
IL_000b: brfalse.s IL_0028 // Customer == null → false
IL_000d: ldloc.0
IL_000e: callvirt instance class Address Customer::get_Address()
IL_0013: stloc.1 // Address 캐싱
IL_0014: ldloc.1
IL_0015: brfalse.s IL_0028 // Address == null → false
IL_0017: ldloc.1
IL_0018: callvirt instance string Address::get_Country()
IL_001d: ldstr "KR"
IL_0022: call bool String::op_Equality(string, string)
IL_0027: ret
IL_0028: ldc.i4.0
IL_0029: ret
}
.method public hidebysig static bool DottedMatch(class Order order) cil managed
{
// Code size: 42 (0x2a) ← NestedMatch와 동일
.locals init ([0] class Customer, [1] class Address)
IL_0000: ldarg.0
IL_0001: brfalse.s IL_0028
IL_0003: ldarg.0
IL_0004: callvirt instance class Customer Order::get_Customer()
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: brfalse.s IL_0028
IL_000d: ldloc.0
IL_000e: callvirt instance class Address Customer::get_Address()
IL_0013: stloc.1
IL_0014: ldloc.1
IL_0015: brfalse.s IL_0028
IL_0017: ldloc.1
IL_0018: callvirt instance string Address::get_Country()
IL_001d: ldstr "KR"
IL_0022: call bool String::op_Equality(string, string)
IL_0027: ret
IL_0028: ldc.i4.0
IL_0029: ret
}
코드 사이즈도 42바이트로 같고 명령어 시퀀스도 한 줄도 다르지 않습니다. 확장 속성 패턴은 순수한 문법 설탕(syntactic sugar) 입니다 — 가독성만 올려주고 런타임은 그대로입니다.
3.2 자동 null 체크의 구조
위 IL에서 우리가 작성하지 않은 작업이 셋 있습니다.
| IL 위치 | 컴파일러가 자동 삽입한 작업 |
|---|---|
IL_0001: brfalse.s |
order 자체가 null인지 확인 |
IL_000b: brfalse.s |
order.Customer가 null인지 확인 |
IL_0015: brfalse.s |
order.Customer.Address가 null인지 확인 |
각 단계에서 null이 발견되면 즉시 IL_0028로 점프해 false를 반환합니다. 이 동작이 우리에게 두 가지 보장을 줍니다.
- NRE 안전성: 중간 객체가 null이어도
NullReferenceException이 터지지 않습니다. - 단락 평가: 앞쪽에서 실패하면 뒤쪽 getter는 호출되지 않습니다 — 비싼 계산을 피할 수 있습니다.
3.3 struct 프로퍼티는 어떻게 다른가
class 프로퍼티는 callvirt로 호출되지만, value type(struct) 프로퍼티는 call로 호출됩니다. Unity의 Vector3, Vector2 같은 struct를 다룰 때 알아둘 만한 차이입니다.
public struct Vec2 { public float X { get; init; } public float Y { get; init; } }
public class Hit { public Vec2 Velocity { get; init; } public int Layer { get; init; } }
public static bool HeavyHit(Hit h)
=> h is { Layer: 9, Velocity.X: > 10f };
.method public hidebysig static bool HeavyHit(class Hit h) cil managed
{
// Code size: 37 (0x25)
.locals init ([0] valuetype Vec2)
IL_0000: ldarg.0
IL_0001: brfalse.s IL_0023 // h == null → false (h만 null 체크)
IL_0003: ldarg.0
IL_0004: callvirt instance int32 Hit::get_Layer() // class 프로퍼티 = callvirt
IL_0009: ldc.i4.s 9
IL_000b: bne.un.s IL_0023 // Layer != 9 → false
IL_000d: ldarg.0
IL_000e: callvirt instance valuetype Vec2 Hit::get_Velocity()
IL_0013: stloc.0
IL_0014: ldloca.s 0
IL_0016: call instance float32 Vec2::get_X() // struct 프로퍼티 = call (가상 호출 X)
IL_001b: ldc.r4 10
IL_0020: cgt
IL_0022: ret
IL_0023: ldc.i4.0
IL_0024: ret
}
- null 체크는
h에 한 번만:Velocity가Vec2struct이므로 null이 될 수 없습니다. 그래서Velocity단계의 brfalse는 생략됐습니다. callvscallvirt:Vec2::get_X는call— virtual 디스패치 비용이 없는 직접 호출입니다. Unity 핫패스(매 프레임 호출되는Update·물리 콜백·AI 틱처럼 성능에 민감한 코드 경로)에서 의미 있는 차이가 됩니다. IL2CPP(Unity가 IL을 C++로 트랜스파일하는 빌드 모드)에서도 이 IL 구조 그대로 변환되므로, struct 프로퍼티 매칭은 모바일 AOT 빌드에서도 가상 호출 오버헤드가 없습니다.
4. [실전 적용] — 관계·논리 패턴과 자유롭게 섞기
속성 패턴이 진짜 빛나는 순간은 다른 패턴과 합성될 때입니다.
4.1 관계 패턴 + 논리 패턴 조합
// Before — 직접 쓴 if 사슬
void Decide(Order order)
{
if (order != null
&& order.Amount > 100 && order.Amount <= 1000
&& order.Status != "Failed")
{
Process(order);
}
}
// After — 속성 + 관계 + 논리 패턴 조합
void Decide(Order order)
{
if (order is { Amount: > 100 and <= 1000, Status: not "Failed" })
{
Process(order);
}
}
콜론 뒤에 들어가는 패턴이 무엇이든 됩니다.
| 패턴 종류 | 예시 | 의미 |
|---|---|---|
| 상수 | Status: "Paid" |
같음 비교 |
| 관계 | HP: < 10 |
부등호 비교 |
논리 and |
HP: > 0 and < 10 |
양쪽 다 만족 |
논리 or |
Type: "S" or "M" |
한쪽이라도 만족 |
논리 not |
Status: not "Failed" |
부정 |
null |
Customer: not null |
null 검사 |
| 중첩 | Address: { City: "Seoul" } |
또 다른 속성 패턴 |
| 점 표기 (C# 10+) | Address.City: "Seoul" |
평탄한 중첩 |
4.2 Unity 실전 — Player 상태 분기
게임 AI가 플레이어 상태에 따라 행동을 결정하는 흔한 시나리오입니다.
public class StatusEffects { public bool IsStunned { get; set; } public bool IsBurning { get; set; } }
public class PlayerStats { public int HP { get; set; } public int Stamina { get; set; } public StatusEffects Status { get; } = new(); }
public class Player { public PlayerStats Stats { get; } = new(); }
public class EnemyAI
{
public void DecideAction(Player player)
{
switch (player)
{
// 기절했고 HP가 낮음 → 마무리
case { Stats.Status.IsStunned: true, Stats.HP: < 30 }:
ExecuteFinisher();
break;
// 기절은 아니지만 스태미나 0 + HP 낮음 → 압박
case { Stats.Status.IsStunned: false, Stats.Stamina: 0, Stats.HP: < 50 }:
ApplyPressure();
break;
// 화상 디버프만 있음 → 회피 행동
case { Stats.Status: { IsBurning: true, IsStunned: false } }:
Reposition();
break;
default:
BasicAttack();
break;
}
}
void ExecuteFinisher() { } void ApplyPressure() { } void Reposition() { } void BasicAttack() { }
}
if-else if 사슬로 쓰면 같은 로직이 30줄을 넘어갑니다. 속성 패턴은 분기 조건을 한 줄로 압축해 분기 자체에 시선을 집중하게 만듭니다.
4.3 Unity 실전 — 충돌 콜라이더 분기
public class HitInfo
{
public int Layer { get; init; }
public Vector2 RelativeVelocity { get; init; } // struct
public bool IsCritical { get; init; }
}
void OnHit(HitInfo hit)
{
// Layer 9(Enemy)이고 충격이 강한 크리티컬 — 큰 피해
if (hit is { Layer: 9, IsCritical: true, RelativeVelocity.X: > 20f })
{
TakeHeavyDamage();
return;
}
// 일반 적과의 충돌 — 작은 피해
if (hit is { Layer: 9, RelativeVelocity.X: > 5f })
{
TakeLightDamage();
return;
}
}
void TakeHeavyDamage() { } void TakeLightDamage() { }
public struct Vector2 { public float X { get; init; } public float Y { get; init; } }
핵심은 RelativeVelocity.X 처럼 struct 멤버까지 점 표기로 그대로 들어간다는 것입니다 — IL 레벨에서는 call get_X()로 풀려 GC 압박도 없습니다.
4.4 단락 평가는 정말 보장되는가?
세 프로퍼티 모두 검사하는 패턴이 있다고 할 때, 첫 번째에서 실패하면 나머지는 호출되지 않을까요? IL로 확인합니다.
public static bool LowAll(Player p)
=> p is { HP: < 10, Stamina: < 10, Mana: < 10 };
.method public hidebysig static bool LowAll(class Player p) cil managed
{
// Code size: 36 (0x24)
IL_0000: ldarg.0
IL_0001: brfalse.s IL_0022 // p == null → false
IL_0003: ldarg.0
IL_0004: callvirt instance int32 Player::get_HP()
IL_0009: ldc.i4.s 10
IL_000b: bge.s IL_0022 // HP >= 10 → false (Stamina/Mana getter 안 호출)
IL_000d: ldarg.0
IL_000e: callvirt instance int32 Player::get_Stamina()
IL_0013: ldc.i4.s 10
IL_0015: bge.s IL_0022 // Stamina >= 10 → false (Mana getter 안 호출)
IL_0017: ldarg.0
IL_0018: callvirt instance int32 Player::get_Mana()
IL_001d: ldc.i4.s 10
IL_001f: clt
IL_0021: ret
IL_0022: ldc.i4.0
IL_0023: ret
}
HP가 10 이상이면 bge.s IL_0022로 곧장 false 반환부로 점프합니다. get_Stamina, get_Mana는 호출되지 않습니다. 단락 평가가 IL 레벨에서 보장됩니다. 즉, 비싼 getter는 뒤쪽에 두는 것이 유리합니다.
5. [함정과 주의사항]
5.1 함정 1: 중간 null이 NRE가 아니라 false
자동 null 체크는 안전하지만, "데이터가 누락됐다"와 "조건에 맞지 않다"가 섞여 보입니다.
// ❌ 의도와 다른 동작 — Customer가 누락된 데이터인데 그냥 통과
if (order is { Customer.Address.Country: "KR" })
{
Ship(order); // Customer가 null인 주문도 false로 분기 → 별도 처리 안 됨
}
else
{
LogError("한국 외 지역"); // Customer 없는 데이터도 여기 떨어짐
}
// ✅ 누락 데이터를 명시적으로 분리
if (order is null || order.Customer is null)
{
LogError("불완전한 데이터");
return;
}
if (order is { Customer.Address.Country: "KR" })
{
Ship(order);
}
else
{
LogError("한국 외 지역");
}
필수 데이터가 빠지면 안 되는 비즈니스 로직에서는, 패턴 매칭 앞단에 명시적 null 가드를 두는 편이 안전합니다.
5.2 함정 2: 프로퍼티 부수효과·비싼 계산
C#에서 프로퍼티 접근은 본질적으로 메서드 호출입니다. getter 안에서 무거운 계산이나 컬렉션 순회, 캐시 미스, DB 조회가 일어나면 패턴 매칭 한 줄에 숨은 비용이 큽니다.
// ❌ Unity에서 자주 보는 함정 — getter 안에서 GameObject.Find
public class GameObjectInfo
{
public Transform RootTransform => GameObject.Find("Root").transform; // 매번 전체 씬 탐색
public string Tag => "Player";
}
void Tick(GameObjectInfo info)
{
// 한 줄 같지만 RootTransform getter가 매 프레임 GameObject.Find 호출
if (info is { Tag: "Player", RootTransform: not null })
{
DoSomething();
}
}
// ✅ 단순 값 보유형 프로퍼티만 패턴에 사용
public class GameObjectInfo
{
public Transform Root { get; init; } // 미리 계산된 값
public string Tag { get; init; }
}
원칙: 패턴 매칭에 쓰는 프로퍼티는 init/set 으로 단순히 값을 보유하는 것이어야 합니다. 계산은 매칭 전에 끝내 둡니다.
5.3 함정 3: 매칭 순서를 잊으면 비용이 새어나간다
속성 패턴은 코드에 작성된 순서대로 평가됩니다. 비싼 검사를 앞에 두면 단락 평가의 이점이 사라집니다.
// ❌ 비싼 검사가 앞에 — 90%가 첫 검사에서 끝남
if (entity is {
HasComplexBuff: true, // 비싼 계산 — 90%는 false
Type: EntityType.Enemy, // 단순 enum 비교
HP: > 0 // 단순 비교
})
// ✅ 단순한 비교를 앞에 — 빠른 검사로 먼저 거른다
if (entity is {
Type: EntityType.Enemy, // 단순 enum
HP: > 0, // 단순 비교
HasComplexBuff: true // 앞에서 통과한 것만 평가
})
성능이 중요한 핫패스에서는 싸고 자주 실패하는 조건을 왼쪽에 둡니다. 이는 && 사슬에서도 똑같이 적용되는 원칙입니다.
5.4 함정 4: 위치 패턴(record Deconstruct)과 혼동하지 말 것
소괄호 ()로 감싼 매칭은 위치 패턴(positional pattern) 으로, Deconstruct 메서드를 사용하는 다른 메커니즘입니다.
public record Order(string Status, decimal Amount);
// 위치 패턴 — Deconstruct 호출 (다음 주제에서 다룬다)
if (order is ("Paid", > 0)) { ... }
// 속성 패턴 — getter 호출 (이번 주제)
if (order is { Status: "Paid", Amount: > 0 }) { ... }
두 표현은 결과가 같아 보일 수 있지만 호출되는 메서드가 다릅니다. 위치 패턴의 자세한 규칙은 다음 주제(위치 패턴)에서 다룹니다 — 여기서는 "괄호 형태가 다르면 다른 패턴이다"만 기억합니다.
6. [C# 버전별 변화]
6.1 C# 8 (2019) — 속성 패턴 도입
C# 8에서 is 표현식과 switch 표현식이 새로 들어오면서 함께 도입됐습니다. 이때는 콜론 뒤에 상수만 올 수 있는 제약이 있었습니다(이후 C# 9에서 관계·논리 패턴 도입으로 풀림).
// C# 8 — 상수 매칭만 가능했던 시기
if (order is { Status: "Paid" }) { ... }
// 중첩 객체는 중괄호를 계속 열어야 했음
if (order is { Customer: { Address: { Country: "KR" } } }) { ... }
6.2 C# 9 (2020) — 관계·논리 패턴 합성
C# 9의 관계 패턴(>, <, >=, <=)과 논리 패턴(and, or, not)이 속성 패턴과 자유롭게 섞일 수 있게 됐습니다.
// C# 9 — 속성 + 관계 + 논리 패턴 조합
if (order is { Amount: > 100 and <= 1000, Status: not "Failed" }) { ... }
6.3 C# 10 (2021) — 확장 속성 패턴 (점 표기법)
여전히 깊은 중첩에서 들여쓰기가 폭발하는 문제가 남아 있어, C# 10이 점 표기법을 추가했습니다.
// Before — C# 8/9 중첩 매칭
if (order is { Customer: { Address: { Country: "KR", City: "Seoul" } } }) { ... }
// After — C# 10 확장 속성 패턴
if (order is { Customer.Address.Country: "KR", Customer.Address.City: "Seoul" }) { ... }
§3에서 확인했듯 두 표현은 동일한 IL을 생성합니다. 문법 설탕이지만 가독성 개선 효과는 큽니다.
6.4 C# 11~13 — 변화 없음
속성 패턴 자체는 C# 10 이후 큰 변화가 없습니다. C# 11에서 추가된 리스트 패턴(이전 주제)이 패턴 매칭 가족을 확장했고, 속성 패턴은 안정 단계에 들어갔습니다.
7. [정리]
| 키 포인트 | 한 줄 요약 |
|---|---|
| 기본 문법 | obj is { Prop: 패턴, ... } — 객체의 여러 프로퍼티를 한 번에 검사하면서 자동 null 가드 포함 |
| 합성 가능성 | 콜론 뒤에 상수·관계·논리·중첩·점 표기 등 어떤 패턴이든 들어간다 |
| C# 10 점 표기 | { A.B.C: 값 } 은 { A: { B: { C: 값 } } } 와 IL이 완전히 동일 — 순수 문법 설탕 |
| 자동 null 체크 | 중간 객체가 null이면 NRE가 아니라 false. 안전하지만 "누락"과 "조건 불일치"가 섞여 보일 수 있음 |
| 단락 평가 | IL 레벨에서 좌→우 순서 보장. 싸고 자주 실패하는 조건을 왼쪽에 둘 것 |
| struct 프로퍼티 | class는 callvirt, struct는 call. struct는 그 자체로는 null 체크 생략 |
| 함정 | ① 중간 null이 false ② getter 부수효과 ③ 매칭 순서 ④ 위치 패턴 ()과 혼동 |
| 다음 주제 | 위치 패턴(Deconstruct 기반, 소괄호 매칭)에서 record와의 시너지를 다룬다 |
Unity 입문자가 기억할 한 가지: 속성 패턴은 "한 줄 안에 비즈니스 규칙을 그대로 옮겨 적는 도구"입니다. && 사슬로 쓸 분기를 모두 속성 패턴으로 바꿔 보면, 프로젝트의 분기 코드가 평균 30~50% 짧아지고 가독성이 명확히 올라갑니다 — 그러면서도 IL은 손으로 쓴 && 사슬과 동일하니, 공짜로 얻는 가독성입니다.
'C# 기초' 카테고리의 다른 글
| [PART4.제어문: 분기와 반복(8/13)] 위치 패턴 — Deconstruct 기반 구조 분해 매칭 (C# 8) (0) | 2026.04.26 |
|---|---|
| [PART4.제어문: 분기와 반복(7/13)] 튜플 패턴 — 여러 값을 동시에 매칭 (C# 8) (0) | 2026.04.26 |
| [PART4.제어문: 분기와 반복(5/13)] 리스트 패턴 — 배열·리스트의 모양으로 분기 (C# 11) (0) | 2026.04.26 |
| [PART4.제어문: 분기와 반복(4/13)] 패턴 매칭 기초 — is 타입 패턴 (0) | 2026.04.26 |
| [PART4.제어문: 분기와 반복(3/13)] switch 표현식 — 값을 돌려주는 분기 (0) | 2026.04.26 |