레코드(C# 참조)
record
한정자를 사용하여 데이터를 캡슐화하는 내장된 기능을 제공하는 참조 형식을 정의합니다. C# 10에서는 record class
구문을 동의어로 사용하여 참조 형식을 명확히 하고 record struct
를 사용하여 유사한 기능을 가진 값 형식을 정의할 수 있습니다.
레코드에서 기본 생성자를 선언하면 컴파일러는 기본 생성자 매개 변수에 대한 공용 속성을 생성합니다. 레코드에 대한 기본 생성자 매개 변수를 위치 매개 변수라고 합니다. 컴파일러는 기본 생성자 또는 위치 매개 변수를 미러링하는 위치 속성을 만듭니다. 컴파일러는 record
한정자가 없는 형식에서 기본 생성자 매개 변수에 대한 속성을 합성하지 않습니다.
다음 두 예제에서는 record
(또는 record class
) 참조 형식을 보여 줍니다.
public record Person(string FirstName, string LastName);
public record Person
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
};
다음 두 예제에서는 record struct
값 형식을 보여 줍니다.
public readonly record struct Point(double X, double Y, double Z);
public record struct Point
{
public double X { get; init; }
public double Y { get; init; }
public double Z { get; init; }
}
변경할 수 있는 속성 및 필드를 사용하여 레코드를 만들 수도 있습니다.
public record Person
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
};
레코드 구조체는 변경 가능하기도 합니다. 이 경우 위치 레코드 구조체와 위치 매개 변수가 없는 레코드 구조체 둘 다일 수 있습니다.
public record struct DataMeasurement(DateTime TakenAt, double Measurement);
public record struct Point
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
레코드를 변경할 수 있지만, 레코드의 기본적인 의도는 변경할 수 없는 데이터 모델을 지원하는 것입니다. 레코드 형식은 다음과 같은 기능을 제공합니다.
- 변경할 수 없는 속성을 사용하여 참조 형식을 만드는 간결한 구문
- 데이터 중심 참조 형식에 유용한 기본 제공 동작:
- 상속 계층 구조 지원
이전 예제는 참조 형식인 레코드와 값 형식인 레코드 간의 몇 가지 차이점을 보여줍니다.
record
또는record class
는 참조 형식을 선언합니다.class
키워드는 선택 사항이지만 읽는 사람에게 명확성을 줄 수 있습니다.record struct
는 값 형식을 선언합니다.- 위치 속성은
record class
및readonly record struct
에서 ‘변경 불가능’합니다.record struct
에서는 ‘변경 가능’합니다.
이 문서의 나머지 부분에서는 record class
형식과 record struct
형식에 대해 설명합니다. 차이점은 각 섹션에 자세히 설명되어 있습니다. class
와 struct
중에서 결정하는 것과 비슷하게 record class
와 record struct
중에서 결정해야 합니다. ‘레코드’라는 용어는 모든 레코드 형식에 적용되는 동작을 설명하는 데 사용됩니다. record struct
또는 record class
는 각각 구조체 또는 클래스 형식에만 적용되는 동작을 설명하는 데 사용됩니다. record struct
형식은 C# 10에서 도입되었습니다.
속성 정의에 대한 위치 구문
위치 매개 변수를 사용하여 레코드의 속성을 선언하고 인스턴스를 만들 때 속성 값을 초기화할 수 있습니다.
public record Person(string FirstName, string LastName);
public static void Main()
{
Person person = new("Nancy", "Davolio");
Console.WriteLine(person);
// output: Person { FirstName = Nancy, LastName = Davolio }
}
속성 정의에 위치 구문을 사용하는 경우 컴파일러가 다음을 만듭니다.
- 레코드 선언에 제공된 각 위치 매개 변수에 대한 공용 자동 구현 속성.
record
형식 및readonly record struct
형식의 경우: 초기화 전용 속성입니다.record struct
형식의 경우: 읽기/쓰기 속성입니다.
- 매개 변수가 레코드 선언의 위치 매개 변수와 일치하는 기본 생성자.
- 레코드 구조체 형식의 경우 각 필드를 기본값으로 설정하는 매개 변수가 없는 생성자입니다.
- 레코드 선언에 제공된 각 위치 매개 변수에 대한
out
매개 변수를 사용하는Deconstruct
메서드. 메서드는 위치 구문을 사용하여 정의된 속성을 분해합니다. 표준 속성 구문을 사용하여 정의된 속성은 무시됩니다.
컴파일러가 레코드 정의에서 만드는 이러한 요소에 특성을 추가하려고 할 수 있습니다. 위치 레코드의 속성에 적용하는 특성에 ‘대상’을 추가할 수 있습니다. 다음 예제에서는 Person
레코드의 각 속성에 System.Text.Json.Serialization.JsonPropertyNameAttribute를 적용합니다. property:
대상은 특성이 컴파일러 생성 속성에 적용됨을 나타냅니다. 다른 값은 필드에 특성을 적용하기 위한 field:
및 매개 변수에 특성을 적용하기 위한 param:
입니다.
/// <summary>
/// Person record type
/// </summary>
/// <param name="FirstName">First Name</param>
/// <param name="LastName">Last Name</param>
/// <remarks>
/// The person type is a positional record containing the
/// properties for the first and last name. Those properties
/// map to the JSON elements "firstName" and "lastName" when
/// serialized or deserialized.
/// </remarks>
public record Person([property: JsonPropertyName("firstName")] string FirstName,
[property: JsonPropertyName("lastName")] string LastName);
위의 예제에서는 레코드에 대한 XML 문서 주석을 만드는 방법도 보여 줍니다. <param>
태그를 추가하여 기본 생성자의 매개 변수에 대한 문서를 추가할 수 있습니다.
생성된 자동 구현 속성 정의가 원하는 내용이 아니면 동일한 이름의 속성을 직접 정의할 수 있습니다. 예를 들어 내게 필요한 옵션이나 가변성을 변경하거나 get
또는 set
접근자에 대한 구현을 제공할 수 있습니다. 원본에서 속성을 선언하는 경우에는 레코드의 위치 매개 변수에서 초기화해야 합니다. 속성이 자동 구체화된 속성인 경우 속성을 초기화해야 합니다. 원본에 지원 필드를 추가하는 경우 지원 필드를 초기화해야 합니다. 생성된 분해자는 속성 정의를 사용합니다. 예를 들어 다음 예제에서는 위치 레코드 public
의 FirstName
및 LastName
속성을 선언하지만 Id
위치 매개 변수를 internal
로 제한합니다. 레코드 및 레코드 구조체 형식에 대해 이 구문을 사용할 수 있습니다.
public record Person(string FirstName, string LastName, string Id)
{
internal string Id { get; init; } = Id;
}
public static void Main()
{
Person person = new("Nancy", "Davolio", "12345");
Console.WriteLine(person.FirstName); //output: Nancy
}
레코드 형식은 위치 속성을 선언할 필요가 없습니다. 다음 예제와 같이 위치 속성 없이 레코드를 선언하고 기타 필드 및 속성을 선언할 수 있습니다.
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; } = [];
};
표준 속성 구문을 사용하여 속성을 정의하지만 액세스 한정자를 생략하면 속성은 암시적으로 private
입니다.
불변성
‘위치 레코드’ 및 ‘위치 읽기 전용 레코드 구조체’는 초기화 전용 속성을 선언합니다. ‘위치 레코드 구조체’는 읽기-쓰기 속성을 선언합니다. 이전 섹션에 표시된 대로 이 두 기본값 중 하나를 재정의할 수 있습니다.
불변성은 데이터 중심 형식이 스레드로부터 안전해야 하거나 해시 테이블에서 동일하게 남아 있는 해시 코드를 사용하는 경우에 유용할 수 있습니다. 하지만 불변성이 모든 데이터 시나리오에 적합한 것은 아닙니다. 예를 들어, Entity Framework Core는 변경할 수 없는 엔터티 형식을 사용한 업데이트를 지원하지 않습니다.
위치 매개 변수(record class
및 readonly record struct
)에서 생성되든 init
접근자를 지정하여 생성되든, 초기화 전용 속성에는 ‘단순 불변성’이 있습니다. 초기화 후에는 값 형식 속성의 값 또는 참조 형식 속성의 참조를 변경할 수 없습니다. 그러나 참조 형식 속성이 참조하는 데이터는 변경할 수 있습니다. 다음 예제에서는 참조 형식 변경 불가능 속성의 콘텐츠(이 경우에는 배열)를 변경할 수 있음을 보여 줍니다.
public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static void Main()
{
Person person = new("Nancy", "Davolio", new string[1] { "555-1234" });
Console.WriteLine(person.PhoneNumbers[0]); // output: 555-1234
person.PhoneNumbers[0] = "555-6789";
Console.WriteLine(person.PhoneNumbers[0]); // output: 555-6789
}
레코드 형식에 고유한 기능이 컴파일러 합성 메서드로 구현되고, 이러한 메서드는 개체 상태를 수정하여 불변성을 손상하지 않습니다. 지정하지 않으면 record
, record struct
, readonly record struct
선언에 대해 합성된 메서드가 생성됩니다.
값 같음
같음 메서드를 재정의하거나 대체하지 않으면 선언하는 형식이 같음 정의 방법을 제어합니다.
class
형식의 경우 두 개체가 메모리에서 동일한 개체를 참조하면 두 개체는 동일합니다.struct
형식의 경우 두 개체가 동일한 형식을 갖고 동일한 값을 저장하면 두 개체는 동일합니다.record
한정자(record class
,record struct
및readonly record struct
)가 있는 형식의 경우 두 개체가 동일한 형식이고 동일한 값을 저장하는 경우 두 개체는 동일합니다.
record struct
에 대한 같음의 정의는 struct
에 대한 정의와 동일합니다. 차이점은 struct
의 경우 구현이 ValueType.Equals(Object)에 있고 리플렉션에 의존한다는 것입니다. 레코드의 경우 구현은 컴파일러가 합성하며 선언된 데이터 멤버를 사용합니다.
일부 데이터 모델에서는 참조 같음이 필요합니다. 예를 들어, Entity Framework Core는 참조 같음을 사용하여 개념적으로 하나의 엔터티에 해당하는 엔터티 형식의 인스턴스를 하나만 사용하는지 확인합니다. 이러한 이유로 레코드 및 레코드 구조체는 Entity Framework Core에서 엔터티 형식으로 사용하기에 적절하지 않습니다.
다음 예제에서는 레코드 형식의 값 같음을 보여 줍니다.
public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static void Main()
{
var phoneNumbers = new string[2];
Person person1 = new("Nancy", "Davolio", phoneNumbers);
Person person2 = new("Nancy", "Davolio", phoneNumbers);
Console.WriteLine(person1 == person2); // output: True
person1.PhoneNumbers[0] = "555-1234";
Console.WriteLine(person1 == person2); // output: True
Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
}
값 같음을 구현하기 위해 컴파일러는 다음을 비롯한 여러 메서드를 합성합니다.
Object.Equals(Object)의 재정의. 재정의가 명시적으로 선언된 경우 오류입니다.
두 매개 변수가 모두 Null이 아닌 경우 이 메서드가 Object.Equals(Object, Object) 정적 메서드의 기본으로 사용됩니다.
R
이(가) 레코드 형식인virtual
또는sealed
,Equals(R? other)
. 이 메서드는 IEquatable<T>를 구현합니다. 이 메서드는 명시적으로 선언할 수 있습니다.레코드 형식이 기본 레코드 형식
Base
,Equals(Base? other)
에서 파생된 경우. 재정의가 명시적으로 선언된 경우 오류입니다.Equals(R? other)
의 고유한 구현을 제공하는 경우GetHashCode
의 구현도 제공하세요.Object.GetHashCode()의 재정의. 이 메서드는 명시적으로 선언할 수 있습니다.
연산자
==
및!=
의 재정의. 연산자가 명시적으로 선언된 경우 오류입니다.레코드 형식이 기본 레코드 형식
protected override Type EqualityContract { get; };
에서 파생된 경우. 이 속성은 명시적으로 선언할 수 있습니다. 자세한 내용은 상속 계층 구조의 같음을 참조하세요.
레코드 형식에 명시적으로 선언할 수 있는 합성된 메서드의 서명과 일치하는 메서드가 있는 경우 컴파일러는 메서드를 합성하지 않습니다.
비파괴적 변경
약간의 수정이 있는 인스턴스를 복사해야 하는 경우 with
식을 사용하여 ‘비파괴적 변형’을 구현할 수 있습니다. with
식은 기존 레코드 인스턴스의 지정된 속성 및 필드가 수정된 복사본인 새 레코드 인스턴스를 만듭니다. 다음 예제와 같이 개체 이니셜라이저 구문을 사용하여 변경할 값을 지정합니다.
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; }
}
public static void Main()
{
Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
Console.WriteLine(person1);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Person person2 = person1 with { FirstName = "John" };
Console.WriteLine(person2);
// output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False
person2 = person1 with { PhoneNumbers = new string[1] };
Console.WriteLine(person2);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False
person2 = person1 with { };
Console.WriteLine(person1 == person2); // output: True
}
with
식은 위치 속성 또는 표준 속성 구문을 사용하여 만든 속성을 설정할 수 있습니다. 명시적으로 선언된 속성에는 with
식에서 변경할 init
또는 set
접근자가 있어야 합니다.
with
식의 결과는 ‘단순 복사본’입니다. 즉, 참조 속성의 경우 인스턴스에 대한 참조만 복사됩니다. 원본 레코드와 복사본은 모두 동일한 인스턴스를 참조합니다.
record class
형식에 대해 이 기능을 구현하기 위해 컴파일러는 clone 메서드와 복사 생성자를 합성합니다. 가상 clone 메서드는 복사 생성자에 의해 초기화된 새 레코드를 반환합니다. with
식을 사용하는 경우 컴파일러는 clone 메서드를 호출하는 코드를 만든 다음, with
식에 지정된 속성을 설정합니다.
다른 복사 동작이 필요한 경우 record class
에서 고유한 복사 생성자를 작성할 수 있습니다. 이렇게 하면 컴파일러는 생성자를 합성하지 않습니다. 레코드가 sealed
면 생성자를 private
로 설정하고 그렇지 않으면 protected
로 설정합니다. 컴파일러는 record struct
형식에 대해 복사 생성자를 합성하지 않습니다. 작성할 수도 있지만, 컴파일러가 with
식에 대해 이것의 호출을 생성하지 않습니다. record struct
의 값은 할당할 때 복사됩니다.
clone 메서드를 재정의할 수 없으며, 어떤 레코드 형식으로도 Clone
이라는 멤버를 만들 수 없습니다. Clone 메서드의 실제 이름은 컴파일러에서 생성합니다.
표시를 위한 기본 제공 형식
레코드 형식에는 공용 속성 및 필드의 이름과 값을 표시하는 컴파일러 생성 ToString 메서드가 있습니다. ToString
메서드는 다음 형식의 문자열을 반환합니다.
<레코드 형식 이름> { <속성 이름> = <값>, <속성 이름> = <값>, ...}
<value>
에 대해 인쇄되는 문자열은 속성의 형식에 대해 ToString()에서 반환하는 문자열입니다. 다음 예제에서 ChildNames
는 System.Array이며, 여기서 ToString
은 System.String[]
을 반환합니다.
Person { FirstName = Nancy, LastName = Davolio, ChildNames = System.String[] }
record class
형식에서 이 기능을 구현하기 위해 컴파일러는 가상 PrintMembers
메서드와 ToString 재정의를 합성합니다. record struct
형식에서 이 멤버는 private
입니다.
ToString
재정의는 형식 이름과 그 뒤의 여는 괄호를 사용하여 StringBuilder 개체를 만듭니다. PrintMembers
를 호출하여 속성 이름 및 값을 추가한 다음 닫는 괄호를 추가합니다. 다음 예제에서는 합성된 재정의에 포함된 것과 유사한 코드를 보여 줍니다.
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Teacher"); // type name
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(" ");
}
stringBuilder.Append("}");
return stringBuilder.ToString();
}
PrintMembers
또는 ToString
재정의의 고유한 구현을 제공할 수 있습니다. 예제는 이 문서의 뒷부분에 나오는 파생 레코드의 PrintMembers
형식 섹션에 나와 있습니다. C# 10 이상에서 ToString
의 구현에는 sealed
한정자가 포함될 수 있으며, 컴파일러가 파생된 레코드에 대해 ToString
구현을 합성할 수 없도록 합니다. record
형식의 계층 구조 전체에서 일관된 문자열 표현을 만들 수 있습니다. (파생 레코드에는 여전히 모든 파생 속성에 대해 생성된 PrintMembers
메서드가 있습니다.)
상속
이 섹션은 record class
형식에만 적용됩니다.
레코드는 다른 레코드에서 상속될 수 있습니다. 그러나 레코드는 클래스에서 상속될 수 없고 클래스는 레코드에서 상속될 수 없습니다.
파생 레코드 형식의 위치 매개 변수
파생 레코드는 기본 레코드 기본 생성자의 모든 매개 변수에 대한 위치 매개 변수를 선언합니다. 기본 레코드는 이러한 속성을 선언하고 초기화합니다. 파생 레코드는 이러한 속성을 숨기지는 않지만 기본 레코드에 선언되지 않은 매개 변수의 속성만 만들고 초기화합니다.
다음 예제에서는 위치 속성 구문을 사용한 상속을 보여 줍니다.
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}
상속 계층 구조에서의 같음
이 섹션은 record class
형식에 적용되지만 record struct
형식에는 적용되지 않습니다. 두 레코드 변수가 같으려면 런타임 형식이 동일해야 합니다. 포함하는 변수의 형식은 다를 수 있습니다. 다음 코드 예제에서는 상속된 같음 비교가 설명되어 있습니다.
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Person student = new Student("Nancy", "Davolio", 3);
Console.WriteLine(teacher == student); // output: False
Student student2 = new Student("Nancy", "Davolio", 3);
Console.WriteLine(student2 == student); // output: True
}
예제에서는 인스턴스가 Student
또는 Teacher
의 파생 형식인 경우에도 모든 변수는 Person
으로 선언됩니다. 인스턴스에는 동일한 속성 및 동일한 속성 값이 있습니다. 그러나 모두 Person
형식 변수이지만 student == teacher
는 False
를 반환하고, 하나는 Person
변수이고 하나는 Student
변수이지만 student == student2
는 True
를 반환합니다. 같음 테스트는 변수의 선언된 형식이 아니라 실제 개체의 런타임 형식에 따라 달라집니다.
이 동작을 구현하기 위해 컴파일러는 레코드 형식과 일치하는 Type 개체를 반환하는 EqualityContract
속성을 합성합니다. EqualityContract
를 사용하면 같음 메서드는 같음을 확인할 때 개체의 런타임 형식을 비교할 수 있습니다. 레코드의 기본 형식이 object
이면 이 속성은 virtual
입니다. 기본 형식이 또 다른 레코드 형식이면 이 속성은 재정의입니다. 레코드 형식이 sealed
면 형식은 sealed
가 되므로, 이 속성은 실제로는 sealed
가 됩니다.
코드가 파생 형식의 두 인스턴스를 비교할 때 합성된 같음 메서드는 기본의 모든 데이터 멤버와 파생 형식의 같음을 확인합니다. 합성된 GetHashCode
메서드는 기본 형식 및 파생 레코드 형식에 선언된 모든 데이터 멤버의 GetHashCode
메서드를 사용합니다. record
데이터 멤버에는 자동 구체화된 속성에 대해 선언된 모든 필드와 컴파일러 합성 지원 필드가 포함됩니다.
파생 레코드의 with
식
with
식의 결과는 식의 피연산자와 동일한 런타임 형식을 갖습니다. 런타임 형식의 속성은 모두 복사되지만 다음 예제와 같이 컴파일 시간 형식의 속성만 설정할 수 있습니다.
public record Point(int X, int Y)
{
public int Zbase { get; set; }
};
public record NamedPoint(string Name, int X, int Y) : Point(X, Y)
{
public int Zderived { get; set; }
};
public static void Main()
{
Point p1 = new NamedPoint("A", 1, 2) { Zbase = 3, Zderived = 4 };
Point p2 = p1 with { X = 5, Y = 6, Zbase = 7 }; // Can't set Name or Zderived
Console.WriteLine(p2 is NamedPoint); // output: True
Console.WriteLine(p2);
// output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = A, Zderived = 4 }
Point p3 = (NamedPoint)p1 with { Name = "B", X = 5, Y = 6, Zbase = 7, Zderived = 8 };
Console.WriteLine(p3);
// output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = B, Zderived = 8 }
}
파생 레코드의 PrintMembers
형식
파생 레코드 형식의 합성된 PrintMembers
메서드는 기본 구현을 호출합니다. 그러면 다음 예제와 같이 파생된 형식과 기본 형식의 모든 공용 속성 및 필드가 ToString
출력에 포함됩니다.
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}
PrintMembers
메서드의 고유한 구현을 제공할 수 있습니다. 이렇게 하려면 다음 서명을 사용합니다.
object
에서 파생되는sealed
레코드(기본 레코드를 선언하지 않음):private bool PrintMembers(StringBuilder builder)
- 다른 레코드에서 파생되는
sealed
레코드의 경우(바깥쪽 형식이sealed
이므로 메서드는 실제로는sealed
입니다):protected override bool PrintMembers(StringBuilder builder)
sealed
가 아니고 개체에서 파생된 레코드:protected virtual bool PrintMembers(StringBuilder builder);
sealed
가 아니고 다른 레코드에서 파생된 레코드:protected override bool PrintMembers(StringBuilder builder);
다음은 합성된 PrintMembers
메서드를 대체하는 코드의 예제입니다. 하나는 개체에서 파생되는 레코드 형식에 대한 것이고 다른 하나는 다른 레코드에서 파생되는 레코드 형식에 대한 것입니다.
public abstract record Person(string FirstName, string LastName, string[] PhoneNumbers)
{
protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"FirstName = {FirstName}, LastName = {LastName}, ");
stringBuilder.Append($"PhoneNumber1 = {PhoneNumbers[0]}, PhoneNumber2 = {PhoneNumbers[1]}");
return true;
}
}
public record Teacher(string FirstName, string LastName, string[] PhoneNumbers, int Grade)
: Person(FirstName, LastName, PhoneNumbers)
{
protected override bool PrintMembers(StringBuilder stringBuilder)
{
if (base.PrintMembers(stringBuilder))
{
stringBuilder.Append(", ");
};
stringBuilder.Append($"Grade = {Grade}");
return true;
}
};
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", new string[2] { "555-1234", "555-6789" }, 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, PhoneNumber1 = 555-1234, PhoneNumber2 = 555-6789, Grade = 3 }
}
참고 항목
C# 10.0 이상에서 컴파일러는 기본 레코드가 ToString
메서드를 봉인한 경우에도 파생된 레코드에서 PrintMembers
를 합성합니다. PrintMembers
의 고유한 구현을 만들 수도 있습니다.
파생 레코드의 분해자 동작
파생 레코드의 Deconstruct
메서드는 컴파일 시간 형식의 모든 위치 속성 값을 반환합니다. 변수 형식이 기본 레코드인 경우 개체가 파생 형식으로 캐스팅되는 경우를 제외하고는 기본 레코드 속성만 분해됩니다. 다음 예제에서는 파생 레코드에 대해 분해자를 호출하는 방법을 보여 줍니다.
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
var (firstName, lastName) = teacher; // Doesn't deconstruct Grade
Console.WriteLine($"{firstName}, {lastName}");// output: Nancy, Davolio
var (fName, lName, grade) = (Teacher)teacher;
Console.WriteLine($"{fName}, {lName}, {grade}");// output: Nancy, Davolio, 3
}
제네릭 제약 조건
record
키워드는 class
또는 struct
형식의 한정자입니다. record
한정자를 추가하면 이 문서의 앞부분에서 설명한 동작이 포함됩니다. 형식이 레코드가 되어야 하는 제네릭 제약 조건은 없습니다. record class
은(는) class
제약 조건을 충족합니다. record struct
은(는) struct
제약 조건을 충족합니다. 자세한 내용은 형식 매개 변수에 대한 제약 조건을 참조하세요.
C# 언어 사양
자세한 내용은 C# 언어 사양의 클래스 섹션을 참조하세요.
이러한 기능에 대한 자세한 내용은 다음 기능 제안 노트를 참조하세요.
참고 항목
.NET
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기