Общие сведения о типах записей в C#

Запись в C# — это класс или структуру, которая предоставляет специальный синтаксис и поведение для работы с моделями данных. Модификатор record указывает компилятору синтезировать элементы, которые полезны для типов, основная роль которых хранит данные. Эти члены включают перегрузку ToString() и члены, поддерживающие равенство значений.

Когда следует использовать записи

Рекомендуется использовать запись вместо класса или структуры в следующих сценариях:

  • Необходимо определить модель данных, зависящую от равенства значений.
  • Необходимо определить тип, для которого объекты являются неизменяемыми.

Равенство значений

Для записей равенство значений означает, что две переменные типа "запись" равны, если совпадают типы и все значения свойств и полей. Для других ссылочных типов, таких как классы, равенство означает равенство ссылок. То есть две переменные типа "класс" равны, если они ссылаются на один и тот же объект. Методы и операторы, определяющие равенство двух экземпляров записи, используют равенство значений.

Не все модели данных хорошо работают с равенством значений. Например, Entity Framework Core использует ссылочное равенство, чтобы гарантировать использование только одного экземпляра типа сущности в том случае, когда разные объекты концептуально являются одной сущностью. По этой причине типы записей не подходят для использования в качестве типов сущностей в Entity Framework Core.

Неизменяемость

Неизменяемый тип — это тип, который не позволяет изменять значения свойств или полей объекта после его создания. Неизменность может быть полезной, если требуется обеспечить потокобезопасность типа или если существует зависимость от хэш-кода, остающегося неизменным в хэш-таблице. Записи предоставляют краткий синтаксис для создания неизменяемых типов и работы с ними.

Неизменяемость подходит не для всех сценариев данных. Entity Framework Core, например, не поддерживает обновление с неизменяемыми типами сущностей.

Как записи отличаются от классов и структур

Тот же синтаксис, который объявляет и создает экземпляры классов или структур, можно использовать с записями. Просто замените class ключевое слово recordили используйте record struct вместо structнего. Аналогичным образом, тот же синтаксис для выражения связей наследования поддерживается классами записей. Записи отличаются от классов следующим образом.

  • Для создания и создания экземпляра типа с неизменяемыми свойствами можно использовать позиционные параметры в основном конструкторе .
  • Те же методы и операторы, которые указывают на равенство или неравенство ссылок в классах (например Object.Equals(Object) и ==), указывают на равенство или неравенство значений в записях.
  • Можно использовать выражение with для создания копии неизменяемого объекта с новыми значениями в выбранных свойствах.
  • Метод записи ToString создает форматированную строку, содержащую имя типа объекта, а также имена и значения всех его открытых свойств.
  • Запись может наследовать от другой записи. Запись не может наследовать от класса, а класс не может наследовать от записи.

Структуры записей отличаются от структур, которые компилятор синтезирует методы для равенства и ToString. Компилятор синтезирует Deconstruct метод для структур позиционной записи.

Компилятор синтезирует открытое свойство только для инициализации для каждого основного параметра конструктора в объекте record class. В компиляторе record structсинтезируется общедоступное свойство чтения и записи. Компилятор не создает свойства для основных параметров class конструктора и struct типов, которые не включают record модификатор.

Примеры

В следующем примере определяется открытая запись, которая использует позиционные параметры для объявления и создания экземпляра. Затем он выводит значения имени и свойства типа:


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#.