값 같음과 구조 분해
레코드의 구조적 같음을 이해하고 Equals/GetHashCode를 재정의하며 구조 분해 패턴을 사용합니다.
값 같음과 구조 분해은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
레코드 동등성 심층 분석
레코드는 모든 속성을 구조적으로 비교하는 Equals, GetHashCode 및 ==/!= 연산자를 자동으로 생성합니다. 이 동작을 이해하면 레코드를 올바르게 사용하고 필요할 때 재정의하는 데 도움이 됩니다.
자동 생성 동등성의 작동 방식
컴파일러는 EqualityComparer<T>.Default를 사용하여 각 속성을 비교하는 코드를 생성합니다. 참조 형식 속성의 경우 이는 해당 형식 자체의 Equals이며, 참조 동등성이 아닙니다.
public record Address(string Street, string City);
public record Person(string Name, Address HomeAddress);
var a = new Person("Alice", new Address("123 Main", "NYC"));
var b = new Person("Alice", new Address("123 Main", "NYC"));
Console.WriteLine(a == b); // True — deep structural equality
// Equality checks:
// Name: "Alice" == "Alice" ✓
// HomeAddress: compares Address properties recursively ✓생성된 동등성 재정의하기
사용자 지정 동등성 로직이 필요할 때는 레코드의 Equals와 GetHashCode를 재정의할 수 있습니다. 예를 들어 일부 속성만 비교하도록 만들 수 있습니다.
public record Customer(int Id, string Name, string Email)
{
// Consider customers equal if they have the same ID,
// regardless of name or email changes
public virtual bool Equals(Customer? other)
=> other is not null && Id == other.Id;
public override int GetHashCode() => Id.GetHashCode();
}컬렉션에서 레코드 사용하기
레코드는 구조적 동등성을 사용하여 IEquatable<T>을 구현하므로 사전 키, HashSets, 그리고 LINQ의 Distinct 및 GroupBy에서 올바르게 작동합니다.
public record Tag(string Name, string Color);
var tags = new List<Tag>
{
new("C#", "blue"), new("C#", "blue"), new("dotnet", "purple")
};
var unique = tags.Distinct().ToList(); // [Tag(C#, blue), Tag(dotnet, purple)]
var set = new HashSet<Tag>(tags);
set.Contains(new Tag("C#", "blue")); // true분해 기초
위치 기반 레코드는 각 위치 기반 속성에 대한 out 매개 변수를 포함하는 Deconstruct 메서드를 자동으로 생성합니다. 이를 통해 튜플과 같은 풀어쓰기가 가능합니다.
public record Point(double X, double Y);
public record RGB(byte R, byte G, byte B);
var p = new Point(3.0, 4.0);
var (x, y) = p; // deconstruct
Console.WriteLine($"{x}, {y}");
var color = new RGB(255, 128, 0);
var (r, g, b) = color;
Console.WriteLine($"R={r}, G={g}, B={b}");패턴 매칭에서의 분해
switch 식에서 레코드를 분해하면 강력한 위치 기반 패턴 매칭을 사용할 수 있습니다.
public record Point(int X, int Y);
string Classify(Point p) => p switch
{
(0, 0) => "Origin",
(int x, 0) => $"X-axis at {x}",
(0, int y) => $"Y-axis at {y}",
(int x, int y) when x == y => $"Diagonal at {x}",
(int x, int y) => $"Point ({x}, {y})"
};
Console.WriteLine(Classify(new Point(0, 0))); // Origin
Console.WriteLine(Classify(new Point(3, 3))); // Diagonal at 3사용자 지정 Deconstruct 메서드
위치 기반이 아닌 레코드와 모든 클래스에는 Deconstruct 메서드를 직접 추가할 수 있습니다. 확장 메서드를 사용하여 기존 형식에 분해 기능을 추가할 수도 있습니다.
public class Temperature
{
public double Celsius { get; }
public Temperature(double c) => Celsius = c;
// Manual Deconstruct
public void Deconstruct(out double celsius, out double fahrenheit)
{
celsius = Celsius;
fahrenheit = Celsius * 9 / 5 + 32;
}
}
var t = new Temperature(100);
var (c, f) = t;
Console.WriteLine($"{c}°C = {f}°F"); // 100°C = 212°F분해의 일부 무시하기
분해에서 필요하지 않은 부분을 무시하려면 버리기(_)를 사용하십시오. 튜플의 버리기와 비슷합니다.
public record Order(int Id, string Customer, decimal Total, DateTime Date);
var order = new Order(42, "Alice", 99.99m, DateTime.UtcNow);
// Only want Id and Total
var (id, _, total, _) = order;
Console.WriteLine($"Order {id}: ${total}");
// In switch: ignore some fields
string Classify(Order o) => o switch
{
(_, _, > 1000, _) => "High value",
(_, _, > 100, _) => "Medium value",
_ => "Low value"
};속성 패턴과 위치 기반 패턴 비교
레코드는 위치 기반 패턴(위치 기준)과 속성 패턴(이름 기준)을 모두 지원합니다. 속성이 많은 레코드에서는 속성 패턴이 더 읽기 쉽습니다.
public record Order(int Id, string Status, decimal Total);
// Positional pattern:
string DescribePos(Order o) => o switch
{
(_, "Shipped", > 100) => "High-value shipped",
_ => "Other"
};
// Property pattern (more readable):
string DescribeProp(Order o) => o switch
{
{ Status: "Shipped", Total: > 100 } => "High-value shipped",
{ Status: "Cancelled" } => "Cancelled",
_ => "Other"
};실전: Result 형식 패턴
레코드와 분해를 사용하는 판별된 합집합 스타일의 Result 형식으로, 오류 처리를 함수형으로 접근하는 방식입니다.
public abstract record Result<T>;
public record Success<T>(T Value) : Result<T>;
public record Failure<T>(string Error) : Result<T>;
Result<Order> PlaceOrder(CreateOrderRequest req)
{
if (req.Quantity <= 0)
return new Failure<Order>("Quantity must be positive");
var order = CreateOrder(req);
return new Success<Order>(order);
}
// Consuming:
var result = PlaceOrder(request);
switch (result)
{
case Success<Order>(var order):
return Results.Created($"/orders/{order.Id}", order);
case Failure<Order>(var error):
return Results.BadRequest(error);
}빠른 확인
분해 식에서 버리기(_)를 사용하면 어떤 작업을 수행합니까?
값 동등성과 분해 요약
핵심 요점:
- 자동 생성된 동등성 비교는 모든 속성을 구조적으로 재귀 비교합니다
- 사용자 지정 식별 로직이 필요하면 레코드에서 Equals/GetHashCode를 재정의합니다
- 레코드는 HashSet 요소와 사전 키로 올바르게 작동합니다
- 위치 기반 레코드는 Deconstruct를 자동으로 생성합니다 — var (a, b) = record를 사용합니다
- 버리기 기호(_)를 사용하면 분해할 때 필요하지 않은 위치 값을 무시할 수 있습니다
- 속성 패턴({Status: "X"})은 복잡한 레코드에서 위치 기반 패턴보다 읽기 쉽습니다
자주 묻는 질문
“값 같음과 구조 분해” 강의는 무료인가요?
네 — “값 같음과 구조 분해” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“값 같음과 구조 분해”에서 뭘 배우나요?
레코드의 구조적 같음을 이해하고 Equals/GetHashCode를 재정의하며 구조 분해 패턴을 사용합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
C# Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“값 같음과 구조 분해” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.