LINQ를 사용할 때 데이터를 정렬하거나 조건에 맞게 필터링하는 것은 매우 자주 필요한 기능이다. 특히 OrderBy
, Where
와 함께 MaxBy()
와 MinBy()
를 활용하면, 원하는 요소를 쉽게 뽑아낼 수 있다. 막상 사용하다 보면 InvalidOperationException이나 NullReferenceException과 같은 오류가 발생하는 경우가 많습니다. 이번 글에서는 정렬 및 조건 필터 기본 사용법과 함께, MaxBy/MinBy 사용 시 자주 발생하는 오류 및 해결법을 알아보려고한다.
📚 목차
1. 정렬 및 조건 필터 기본
LINQ에서 OrderBy
와 Where
를 사용하면 데이터를 정렬하고 특정 조건에 맞게 필터링할 수 있다.
예를 들어, 주문 리스트에서 주문 날짜가 특정 기간에 해당하는 데이터만 뽑거나, 제품 가격 기준으로 정렬하는 등의 작업을 할 수 있다.
// 기본 예제: 주문 데이터를 날짜 기준으로 정렬하고, 특정 날짜 이후 주문만 필터링
var filteredOrders = orders
.Where(o => o.OrderDate >= new DateTime(2023, 1, 1))
.OrderBy(o => o.OrderDate);
위 코드는 주문 날짜가 2023년 1월 1일 이후인 주문들을 날짜 순으로 정렬한다.
2. MaxBy/MinBy 사용법
.NET 6부터는 MaxBy()
와 MinBy()
를 사용해 컬렉션 내에서 최대값/최소값 요소를 쉽게 뽑아낼 수 있다.
예를 들어, 상품 리스트에서 가장 비싼 제품이나 가장 최근에 등록된 제품을 찾을 때 유용하다.
// 예제: 상품 리스트에서 가장 높은 가격의 제품 찾기
var mostExpensiveProduct = products.MaxBy(p => p.Price);
// 예제: 주문 리스트에서 가장 최근 주문 찾기
var latestOrder = orders.MaxBy(o => o.OrderDate);
위 코드는 각각 최대 가격과 최대 주문 날짜를 기준으로 해당 요소를 반환한다.
3. 자주 발생하는 오류와 해결법
LINQ 정렬 및 집계 관련해서 자주 발생하는 오류는 다음과 같다:
❌ 오류 1: InvalidOperationException
예: 조건에 맞는 요소가 하나도 없을 때 MaxBy()
나 MinBy()
를 사용하면 발생한다.
System.InvalidOperationException: Sequence contains no elements.
해결 방법: DefaultIfEmpty()
를 사용해 빈 시퀀스에 기본값을 제공하거나, ??
연산자로 결과가 없을 경우 대체값을 지정한다.
// DefaultIfEmpty() 사용 예제
var mostExpensive = products
.Where(p => p.Price.HasValue && p.Price > 1500) // 조건에 맞는 데이터 없음
.DefaultIfEmpty(new Product { Name = "없음", Price = 0 })
.MaxBy(p => p.Price);
Console.WriteLine($"Result: {mostExpensive.Name}, {mostExpensive.Price}"); // "없음, 0"
// ?? 연산자 사용 예제
var mostExpensiveWithNullCoalescing = products
.Where(p => p.Price.HasValue && p.Price > 1500)
.MaxBy(p => p.Price) ?? new Product { Name = "없음", Price = 0 };
Console.WriteLine($"Result: {mostExpensiveWithNullCoalescing.Name}, {mostExpensiveWithNullCoalescing.Price}"); // "없음, 0"
→ DefaultIfEmpty()
는 시퀀스가 비었을 때 기본 요소를 추가하고, ??
는 결과가 null일 때 대체값을 제공한다.
❌ 오류 2: NullReferenceException
예: 정렬 기준이 되는 속성이 null일 경우 발생할 수 있다.
var result = products.OrderBy(p => p.Price).First().ToString(); // 만약 Price가 null이면 오류 발생
해결 방법: 정렬 전 null 여부를 체크하거나, ??
연산자를 사용해 기본값을 지정한다.
// null 체크 후 정렬
var safeResult = products
.Where(p => p.Price.HasValue) // null 제외
.OrderBy(p => p.Price)
.First()
.ToString();
// ?? 연산자로 기본값 지정
var priceOrDefault = products.MaxBy(p => p.Price)?.ToString() ?? "가격 정보 없음";
→ null 체크와 기본값 지정을 통해 예외를 방지할 수 있다.
4. 실전 예제: 상품 리스트 처리
예제 상황: 상품 리스트에서 가격이 0보다 큰 상품 중, 가장 높은 가격의 제품을 찾고, 그 결과를 조건에 따라 필터링해서 보여준다.
🧾 데이터 정의
public class Product
{
public string Name { get; set; }
public decimal? Price { get; set; }
public DateTime RegisteredAt { get; set; }
}
var products = new List
{
new Product { Name = "노트북", Price = 1200, RegisteredAt = new DateTime(2023, 1, 10) },
new Product { Name = "모니터", Price = 800, RegisteredAt = new DateTime(2023, 2, 5) },
new Product { Name = "키보드", Price = null, RegisteredAt = new DateTime(2023, 3, 1) },
new Product { Name = "마우스", Price = 300, RegisteredAt = new DateTime(2023, 1, 20) }
};
🧾 LINQ 코드
// Price가 null이 아닌 상품들 중, 가격이 0보다 큰 것 필터링 후 가장 비싼 제품 찾기
var mostExpensive = products
.Where(p => p.Price.HasValue && p.Price > 0)
.MaxBy(p => p.Price) ?? new Product { Name = "없음", Price = 0 };
var result = mostExpensive;
📌 예상 출력 결과
Product Name: 노트북, Price: 1200, RegisteredAt: 2023-01-10
→ Price가 null인 제품은 제외되고, 가장 높은 가격을 가진 "노트북"이 결과로 나온다.
5. 마무리
정렬과 조건 필터는 실무에서 데이터를 효과적으로 가공하는 데 필수적인 기능이다.OrderBy
, Where
, 그리고 MaxBy()/MinBy()
를 적절히 활용하면 원하는 데이터를 쉽게 뽑아낼 수 있다.
- InvalidOperationException: 조건에 맞는 데이터가 없으면 발생.
DefaultIfEmpty()
로 빈 시퀀스에 기본값을 제공하자. - NullReferenceException: 정렬 기준 null 체크 필수.
??
연산자로 기본값을 지정하면 안전하다. - 예제처럼
DefaultIfEmpty()
는 시퀀스 수준에서,??
는 개별 결과 수준에서 활용 가능.
'Languague > C#' 카테고리의 다른 글
[C# LINQ] 즉시 실행 vs 지연 실행 – Deferred vs Immediate Execution (0) | 2025.05.01 |
---|---|
[C# LINQ] 리스트 포함 여부 확인하기 – Contains vs Any vs Join (0) | 2025.04.18 |
[C# LINQ] 중복 제거하면서 조건 유지하기 – DistinctBy 사용법 & 중복 키 오류 해결 포함 (0) | 2025.04.12 |
[C# LINQ] Join vs GroupJoin 차이점 (0) | 2025.04.10 |
[C# LINQ] GroupJoin 사용법, null 처리(System.NullReferenceException: 'Object referenc (0) | 2025.04.09 |