Quick Reference
tuple은 고정 개수의 값을 간결하게 묶는 type입니다. (T1 Name1, T2 Name2)는 ValueTuple value semantics를 쓰며, 선언·대입·return·deconstruction에서 element name을 읽기 좋게 붙일 수 있습니다.
static (string Name, int Age) GetUser() => ("Mina", 26);
var user = GetUser();
Console.WriteLine(user.Name);
var (name, age) = GetUser();
(_, int onlyAge) = GetUser();ValueTuple은 값 타입,Tuple<T1, T2>는 reference type입니다.- element name은 type identity가 아니라 source/tooling metadata입니다. runtime field는
Item1,Item2계열입니다. Deconstruct(out ...)method가 있으면 tuple이 아닌 type도 분해할 수 있습니다.- 짧은 local result에는 tuple, 장기 public contract·validation·행동에는 named type이나 record를 고릅니다.
선언, 반환, 구조 분해
(int X, int Y) point = (3, 4);
(string, int) unnamed = ("Mina", 26);
static (bool Success, string? Error) Validate(string email)
{
return email.Contains('@')
? (true, null)
: (false, "Missing @");
}
var (success, error) = Validate("mina@example.com");tuple element name은 선언·대입에서 보존되거나 추론될 수 있지만, tuple의 shape는 위치와 element type이 중심입니다. 같은 위치·type의 tuple을 다른 이름으로 바꿨다고 distinct runtime data type이 생기지 않습니다. name은 caller의 이해를 돕지만 serialized schema나 long-lived compatibility contract를 name만으로 보장하지 않습니다.
public sealed class Point(double x, double y)
{
public double X { get; } = x;
public double Y { get; } = y;
public void Deconstruct(out double x, out double y) => (x, y) = (X, Y);
}
var (x, y) = new Point(3, 4);deconstruction은 out parameter pattern을 찾습니다. 필요한 값만 받지 않을 때 _ discard를 쓰고, 별도의 _ local variable과 의미가 충돌하지 않도록 짧은 deconstruction scope에 둡니다.
Tuple, record, class 선택
| 필요 | 선택 | 이유 |
|---|---|---|
| 한 method 안의 짧은 2~3개 결과 | named tuple | 선언·return·deconstruction이 간결 |
| 호출자가 계속 해석할 data shape | record 또는 named class/struct | 이름, validation, documentation을 type으로 고정 |
| reference identity·lifecycle | class | tuple은 identity API가 아님 |
legacy .NET Tuple<T...> API | Tuple<T...> | reference semantics와 ItemN surface를 인지 |
public API가 tuple을 절대 쓸 수 없다는 뜻은 아닙니다. 작은 결과가 명확하고 versioning 비용이 낮으면 유용합니다. 다만 element가 늘거나 의미·validation·serialization 요구가 커지는 순간 named record/class가 caller와 library의 변경을 더 명확히 관리합니다.
tuple은 값 타입이라는 이유만으로 stack allocation을 보장하지 않습니다. 값 복사와 boxing conversion 가능성이 type 계약이고, 실제 allocation은 usage와 runtime implementation에 따라 달라집니다.
자주 틀리는 부분
(bool Success, string Error)처럼 실패 때 null이 가능한 element는 string?로 contract를 드러냅니다. success flag와 error message의 관계가 더 복잡하면 tuple 대신 Result type으로 invalid state를 막으세요.
deconstruction은 object를 clone하지 않습니다. out value를 꺼내는 문법일 뿐이므로, reference element를 분해하면 같은 object reference를 받습니다.
참고 링크
2 sources