Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Record vs Struct в C#: Основные различия
Разница между record и struct в C# является фундаментальной, поскольку эти конструкции предназначены для разных сценариев использования, несмотря на некоторое сходство в поведении.
Ключевые различия в таблице
| Характеристика | Record | Struct |
|---|---|---|
| Тип по умолчанию | Ссылочный тип (class) | Значимый тип |
| Наследование | Поддерживает наследование | Не поддерживает наследование (кроме интерфейсов) |
| Равенство по значению | По умолчанию | Требует реализации |
| Иммутабельность | Рекомендуется, но не обязательна | Обычно изменяема |
| Цель использования | Моделирование данных с семантикой равенства | Небольшие неделимые значения |
Семантика равенства
Record автоматически реализует равенство по значению - два экземпляра считаются равными, если все их свойства имеют одинаковые значения.
public record Person(string Name, int Age);
var person1 = new Person("Анна", 30);
var person2 = new Person("Анна", 30);
Console.WriteLine(person1 == person2); // True - равенство по значению
Struct требует ручной реализации равенства через переопределение Equals() и GetHashCode() для получения аналогичного поведения:
public struct Point
{
public int X { get; init; }
public int Y { get; init; }
public override bool Equals(object obj)
=> obj is Point other && X == other.X && Y == other.Y;
public override int GetHashCode() => HashCode.Combine(X, Y);
}
Иммутабельность и сopy-конструкторы
Record предоставляет удобный синтаксис для создания модифицированных копий с помощью with-выражений:
var original = new Person("Иван", 25);
var modified = original with { Age = 26 };
// Создается новый объект, original остается неизменным
Console.WriteLine(modified); // Person { Name = Иван, Age = 26 }
Struct по умолчанию изменяем, и для иммутабельности нужно явно использовать readonly struct:
public readonly struct ImmutablePoint
{
public int X { get; init; }
public int Y { get; init; }
}
Производительность и allocation
Struct хранится в стеке (или внутри родительского объекта) и имеет лучшую производительность для небольших объектов:
// Не создает объектов в куче
var points = new Point[1000];
Record (как ссылочный тип) хранится в управляемой куче, что может создавать нагрузку на GC при интенсивном создании объектов.
Сценарии использования
Когда использовать struct:
- Маленькие, неделимые значения (координаты, деньги, измерения)
- Когда критична производительность и нужно избегать аллокаций в куче
- Для межплатформенного взаимодействия (P/Invoke)
- Когда нужна семантика копирования по значению
Когда использовать record:
- Модели данных DTO (Data Transfer Objects)
- Объекты предметной области с семантикой равенства
- Конфигурационные объекты
- Результаты запросов и команды
- Когда нужна иммутабельность и удобное копирование
Расширенные возможности records
Record struct (C# 10+) объединяет преимущества обеих концепций:
public record struct Vector3d(double X, double Y, double Z)
{
// Дополнительные члены
public double Magnitude => Math.Sqrt(X * X + Y * Y + Z * Z);
}
// Имеет семантику равенства как у record и хранится в стеке как struct
Заключение
Основное различие заключается в типе хранения (стек vs куча) и семантике равенства. Record идеален для моделирования сложных данных с автоматическим равенством, тогда как struct оптимален для простых значений, где важна производительность. Выбор зависит от конкретных требований: если нужна семантика значений для сложных объектов - record; если критична производительность для простых данных - struct. Начиная с C# 10, record struct предлагает гибридный подход, сочетающий лучшие черты обеих концепций.