C#의 레코드 형식 소개

C#의 레코드는 데이터 모델 작업에 특별한 구문과 동작을 제공하는 클래스 또는 구조체입니다. record 한정자는 주 역할이 데이터를 저장하는 형식에 유용한 멤버를 합성하도록 컴파일러에 지시합니다. 이러한 멤버에는 값 같음을 지원하는 ToString() 및 멤버의 오버로드가 포함됩니다.

레코드를 사용하는 경우

다음 시나리오에서 클래스 또는 구조체 대신 레코드를 사용하는 것이 좋습니다.

  • 값 같음 여부에 따라 달라지는 데이터 모델을 정의하려는 경우
  • 변경할 수 없는 개체의 형식을 정의하려고 합니다.

값 같음

레코드의 경우 값 같음은 형식이 일치하고 모든 속성 및 필드 값이 일치하는 경우 레코드 형식의 두 변수가 같다는 것을 의미합니다. 클래스와 같은 다른 참조 형식의 경우 같음은 참조 같음을 의미합니다. 즉, 클래스 형식의 두 변수는 같은 개체를 참조하는 경우 같습니다. 두 레코드 인스턴스의 같음을 확인하는 메서드와 연산자에서 값 같음을 사용합니다.

일부 데이터 모델은 값 같음을 사용하지 않습니다. 예를 들어, Entity Framework Core는 참조 같음을 사용하여 개념적으로 하나의 엔터티에 해당하는 엔터티 형식의 인스턴스를 하나만 사용하는지 확인합니다. 이러한 이유로 레코드 형식은 Entity Framework Core에서 엔터티 형식으로 사용하기에 적절하지 않습니다.

불변성

변경할 수 없는 형식은 인스턴스화된 후 개체의 속성 또는 필드 값을 변경하는 것을 방지하는 형식입니다. 불변성은 형식이 스레드로부터 안전해야 하거나 해시 테이블에서 동일하게 남아 있는 해시 코드를 사용하는 경우에 유용할 수 있습니다. 레코드는 변경할 수 없는 형식을 만들고 사용하기 위한 간결한 구문을 제공합니다.

불변성은 모든 데이터 시나리오에 적합하지 않습니다. 예를 들어, Entity Framework Core는 변경할 수 없는 엔터티 형식을 사용한 업데이트를 지원하지 않습니다.

레코드가 클래스 및 구조체와 다른 방식

클래스 또는 구조체를 선언하고 인스턴스화하는 동일한 구문을 레코드와 함께 사용할 수 있습니다. class 키워드를 record(으)로 대체하거나 struct 대신 record struct(을)를 사용합니다. 마찬가지로, 상속 관계를 표현하기 위한 동일한 구문은 레코드 클래스에서 지원됩니다. 레코드가 클래스와 다른 점은 다음과 같습니다.

  • 기본 생성자에서 위치 매개 변수를 사용하여 변경할 수 없는 속성을 사용하여 형식을 만들고 인스턴스화할 수 있습니다.
  • 클래스에서 참조 같음 또는 같지 않음(예: Object.Equals(Object)==)을 나타내는 동일한 메서드와 연산자가 레코드에서 값 같음 또는 같지 않음을 나타냅니다.
  • with을 사용하여 선택된 속성에 새 값을 포함하는 변경할 수 없는 개체의 복사본을 만들 수 있습니다.
  • 레코드의 ToString 메서드는 개체 형식 이름과 모든 퍼블릭 속성의 이름과 값을 표시하는 형식 문자열을 만듭니다.
  • 레코드는 다른 레코드에서 상속될 수 있습니다. 레코드는 클래스에서 상속될 수 없으며 클래스는 레코드에서 상속될 수 없습니다.

레코드 구조체는 컴파일러가 같음과 ToString을(를) 위한 메서드를 합성한다는 점에서 구조체와 다릅니다. 컴파일러는 위치 레코드 구조체에 대한 Deconstruct 메서드를 합성합니다.

컴파일러는 record class의 각 기본 생성자 매개 변수에 대한 공개 초기화 전용 속성을 합성합니다. record struct에서 컴파일러는 공개 읽기/쓰기 속성을 합성합니다. 컴파일러는 record 한정자를 포함하지 않는 classstruct 형식에서 기본 생성자 매개 변수에 대한 속성을 만들지 않습니다.

예제

다음 예제에서는 위치 매개 변수를 사용하여 레코드를 선언하고 인스턴스화하는 퍼블릭 레코드를 정의합니다. 그런 다음 형식 이름 및 속성 값을 출력합니다.


public record Person(string FirstName, string LastName);

public static class Program
{
    public static void Main()
    {
        Person person = new("Nancy", "Davolio");
        Console.WriteLine(person);
        // output: Person { FirstName = Nancy, LastName = Davolio }
    }

}

다음 예제에서는 레코드에서 값 같음을 보여 줍니다.

public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static class Program
{
    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
    }
}

다음 예제에서는 with 식을 사용하여 변경할 수 없는 개체를 복사하고 속성 중 하나를 변경하는 방법을 보여 줍니다.

public record Person(string FirstName, string LastName)
{
    public required string[] PhoneNumbers { get; init; }
}

public class Program
{
    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
    }
}

자세한 내용은 레코드(C# 참조)를 참조하세요.

C# 언어 사양

자세한 내용은 C# 언어 사양을 참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다.