C# 튜플(ValueTuple) 정리
C#의 튜플(Tuple) 기능은 여러 데이터 요소를 하나의 가벼운 데이터 구조로 묶는 간결한 구문을 제공한다. 이 글에서는 튜플의 선언, 초기화, 멤버 접근, 주요 사용 사례, 필드 이름 지정, 형식 별칭, 할당 및 구조 분해 등의 내용을 다룬다.
1. 튜플 기본 사용법
(double, int) t1 = (4.5, 3);
Console.WriteLine($"요소 {t1.Item1}와 {t1.Item2}를 가진 튜플.");
// 출력: 요소 4.5와 3를 가진 튜플.
(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"{t2.Count}개의 요소의 합은 {t2.Sum}입니다.");
// 출력: 3개의 요소의 합은 4.5입니다.
- 튜플을 정의할 때는 각 데이터 멤버의 타입과 선택적으로 이름을 지정한다.
- 튜플 타입 내에 메서드는 정의할 수 없지만, .NET에서 제공하는 메서드는 사용할 수 있다.
(double, int) t = (4.5, 3);
Console.WriteLine(t.ToString());
Console.WriteLine($"해시코드: {t.GetHashCode()}");
- 튜플 타입은 값 타입이며, 요소는 public 필드이다. 따라서 변경 가능한 값 타입(mutable struct)이다.
튜플은 매우 많은 수의 요소도 가질 수 있다:
var t = (1, 2, ..., 26); // 최대 26개 이상도 가능
Console.WriteLine(t.Item26); // 출력: 26
2. 튜플의 사용 사례
메서드에서 여러 값 반환
(int min, int max) FindMinMax(int[] input)
{
if (input is null || input.Length == 0)
throw new ArgumentException("배열이 null이거나 비어 있음");
var min = int.MaxValue;
var max = int.MinValue;
foreach (var i in input)
{
if (i < min) min = i;
if (i > max) max = i;
}
return (min, max);
}
사용 예시:
var (minimum, maximum) = FindMinMax(new[] { 1, 5, 9 });
Console.WriteLine($"최솟값: {minimum}, 최댓값: {maximum}");
out
키워드를 사용하는 대신 튜플을 통해 여러 값을 간편하게 반환할 수 있다.- 튜플은 LINQ 쿼리에서도 익명 타입 대신 사용할 수 있다.
- 느슨하게 관련된 데이터 그룹화에 유용하다.
- 공용 API에서는 클래스나 구조체 정의를 고려하는 것이 좋다.
3. 튜플 필드 이름
튜플의 필드 이름은 다음과 같이 명시적으로 지정할 수 있다:
var t = (Sum: 4.5, Count: 3);
Console.WriteLine($"{t.Count}개의 합은 {t.Sum}");
다음과 같이 타입 정의 시에도 지정 가능하다:
(double Sum, int Count) d = (4.5, 3);
필드 이름 자동 추론 (Projection Initializers)
변수명을 필드 이름으로 자동 추론한다:
var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine($"{t.count}개의 합은 {t.sum}");
단, 다음과 같은 경우에는 이름이 자동으로 추론되지 않는다:
- 후보 이름이
Item3
,ToString
,Rest
와 같은 튜플 기본 멤버 이름일 경우 - 중복되는 필드 이름이 존재할 경우
명시적으로 지정하거나 기본 이름(Item1
, Item2
, ...)으로 접근할 수 있다:
var a = 1;
var t = (a, b: 2, 3);
Console.WriteLine(t.Item1); // 1 (a)
Console.WriteLine(t.Item2); // 2 (b)
Console.WriteLine(t.Item3); // 3
컴파일 시 명시적/추론된 이름은 내부적으로 기본 이름으로 대체되며, 런타임에서는 사용할 수 없다.
4. 튜플 타입에 별칭 지정 (C# 12 이상)
using
지시문으로 튜플 타입에 별칭(alias)을 줄 수 있다:
global using BandPass = (int Min, int Max);
BandPass bracket = (40, 100);
Console.WriteLine($"{bracket.Min} ~ {bracket.Max}");
별칭은 새로운 타입을 생성하는 것이 아니라, 기존 튜플 타입에 의미를 부여하는 용도이다.
다음과 같이 구조 분해도 가능하다:
(int a, int b) = bracket;
서로 호환되는 다른 별칭도 사용할 수 있다:
using Range = (int Minimum, int Maximum);
Range r = bracket;
→ 타입과 요소 수만 일치하면 이름이 달라도 할당 가능하다.
※ 진정한 타입 안정성이 필요하다면 Positional Record를 사용하는 것이 더 적절하다.
5. 튜플 할당과 구조 분해
두 튜플 타입 간에 다음 조건을 만족하면 할당이 가능하다:
- 요소의 수가 같음
- 각 요소의 타입이 동일하거나 암시적으로 변환 가능함
(int a, int b) = (1, 2); // 구조 분해
(int, int) t1 = (3, 4);
(int x, int y) = t1;
마무리
튜플은 C#에서 다수의 값을 손쉽게 묶고 처리할 수 있는 매우 유용한 기능이다.
- 일시적 데이터 그룹화
- 메서드 반환
- 구조 분해
- 별칭을 통한 가독성 향상 등 다양한 용도로 활용 가능하다.
단, 공용 API에서는 되도록 클래스를 정의하고, 복잡하거나 재사용이 필요한 구조에는 레코드나 구조체를 고려하는 것이 좋다.
참고
'JS > TIL(Today I Learned)' 카테고리의 다른 글
2025-03-12 <최종 프로젝트 D-2> 리드미 작성 (0) | 2025.03.12 |
---|---|
2025-03-11 <최종 프로젝트 D-3> EC2 서버 Brute Force 공격 대응하기 (0) | 2025.03.11 |
2025-03-10 <최종 프로젝트 D-4> 스트레스 테스트 (1) | 2025.03.10 |
2025-03-07 <최종 프로젝트 D-7> AWS EIP, NLB, 오토 스케일링을 통해 서버 배포하기 (1) | 2025.03.07 |
2025-03-06 <EC2(ubuntu) 도커 초기 환경 설정> (0) | 2025.03.06 |
댓글