Car anotherMyCar = new Car("Honda", "Pilot", "Blue");
Console.WriteLine("Another variable for my car: ");
DisplayCarStats(anotherMyCar);
Console.WriteLine;
// Попытка изменения свойства приводит к ошибке на этапе компиляции.
// myCar.Color = "Red";
Console.ReadLine;
static void DisplayCarStats(Car c)
{
Console.WriteLine("Car Make: {0}", c.Make);
Console.WriteLine("Car Model: {0}", c.Model);
Console.WriteLine("Car Color: {0}", c.Color);
}
Вполне
ожидаемо оба метода создания объекта работают, значения свойств отображаются, а попытка изменить свойство после конструирования приводит к ошибке на этапе компиляции.
Чтобы создать тип записи
CarRecord
, добавьте к проекту новый файл по имени
CarRecord.cs
со следующим кодом:
record CarRecord
{
public string Make { get; init; }
public string Model { get; init; }
public string Color { get; init; }
public CarRecord {}
public CarRecord (string make, string model, string color)
{
Make = make;
Model = model;
Color = color;
}
}
Запустив приведенный далее код из
Program.cs
, вы можете удостовериться в том, что поведение записи
CarRecord
будет таким же, как у класса
Car
со средствами доступа только для инициализации:
Console.WriteLine("/*************** RECORDS *********************/");
// Использовать инициализацию объекта
CarRecord myCarRecord = new CarRecord
{
Make = "Honda",
Model = "Pilot",
Color = "Blue"
};
Console.WriteLine("My car: ");
DisplayCarRecordStats(myCarRecord);
Console.WriteLine;
// Использовать специальный конструктор
CarRecord anotherMyCarRecord = new CarRecord("Honda", "Pilot", "Blue");
Console.WriteLine("Another variable for my car: ");
Console.WriteLine(anotherMyCarRecord.ToString);
Console.WriteLine;
// Попытка изменения свойства приводит к ошибке на этапе компиляции.
// myCarRecord . Color = "Red";
Console.ReadLine;
Хотя мы пока еще не обсуждали эквивалентность (см. следующий раздел) или наследование (см. следующую главу) с типами записей, первое знакомство с записями не создает впечатления, что они обеспечивают большое преимущество. Текущий пример записи
CarRecord
включал весь ожидаемый связующий код. Заметное отличие присутствует в выводе: метод
ToString
для типов записей более причудлив, как видно в показанном ниже фрагменте вывода:
/*************** RECORDS *********************/
My car:
CarRecord { Make = Honda, Model = Pilot, Color = Blue }
Another variable for my car:
CarRecord { Make = Honda, Model = Pilot, Color = Blue }
Но взгляните на следующее обновленное определение записи
Car
:
record CarRecord(string Make, string Model, string Color);
В конструкторе так называемого позиционного типа записи определены свойства записи, а весь остальной связующий код удален. При использовании такого синтаксиса необходимо принимать во внимание три соображения. Во-первых, не разрешено применять инициализацию объектов типов записей, использующих компактный синтаксис определения, во-вторых, запись должна конструироваться со свойствами, расположенными в корректных позициях, и, в-третьих, регистр символов в свойствах конструктора точно повторяется в свойствах внутри типа записи.
Эквивалентность с типами записей
В примере класса
Car
два экземпляра
Car
создавались с одними и теми же данными. В приведенной далее проверке может показаться, что следующие два экземпляра класса эквивалентны:
Console.WriteLine($"Cars are the same? {myCar.Equals(anotherMyCar)}");
// Эквивалентны ли экземпляры Car?
Однако они не эквивалентны. Вспомните, что типы записей представляют собой специализированный вид класса, а классы являются ссылочными типами. Чтобы два ссылочных типа были эквивалентными, они должны указывать на тот же самый объект в памяти. В качестве дальнейшей проверки выясним, указывают ли два экземпляра
Car
на тот же самый объект:
Console.WriteLine($"Cars are the same reference?
{ReferenceEquals(myCar, anotherMyCar)}");
// Указывают ли экземпляры Car на тот же самый объект?
Запуск программы дает приведенный ниже результат:
Cars are the same? False
CarRecords are the same? False
Типы записей ведут себя по-другому. Они неявно переопределяют
Equals
,
==
и
!=
, чтобы производить результаты, как если бы экземпляры были типами значений. Взгляните на следующий код и показанные далее результаты:
Console.WriteLine($"CarRecords are the same?
{myCarRecord.Equals(anotherMyCarRecord)}");
// Эквивалентны ли экземпляры CarRecord?
Console.WriteLine($"CarRecords are the same reference?
{ReferenceEquals(myCarRecord,another
MyCarRecord)}");
// Указывают ли экземпляры CarRecord на тот же самый объект?