Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

4 года назад
Открыть в
День 1187. #ЗаметкиНаПолях Апкаст Записей Интересную особенность записей обнаружил Фил Хаак. Вы не можете сделать апкаст, как для класса. Допустим, у нас есть следующие записи. Базовая (она же DTO для обновления):
public record PersonUpdate()
{
  public string Name {get; init;}
  //... остальные свойства
};

Производная (с добавленным свойством Id):
public record Person(int Id)
  : PersonUpdate() {};

Задача стандартная: получить Person из базы или API, создать PersonUpdate с изменёнными свойствами и отправить его в метод UpdatePerson. Код получается довольно простой:
var person = GetPerson(42);

var updated = (PersonUpdate)person 
  with { Name = "New Name", …};

UpdatePerson(42, updated);

Вроде всё должно работать. Но давайте посмотрим, что у нас получилось в updated:
Console.WriteLine(updated);
// Вывод:
// Person { Name = New Name, Id = 42 }

Свойство обновилось, но тип всё равно производный и содержит Id. Это, конечно, может не быть проблемой, но для Фила стало, т.к. API для обновления принимал объект без свойства Id, а в этом случае выдавал ошибку. Фил спросил сообщество, как решить эту проблему. Предлагались разные варианты от использования маппера до сериализации/десериализации. Но решение нашлось довольно элегантное.
public record PersonUpdate()
{
  //... свойства

  public static PersonUpdate 
   Copy(PersonUpdate updated) => new(updated);
};

Статический метод принимает запись и выдаёт её копию. И действительно:
var updated = PersonUpdate.Copy(person) 
  with { Name = "New Name"};

Console.WriteLine(updated);
// Вывод:
// PersonUpdate { Name = New Name }

Источник: gist.github.com/haacked…7c09d28b