Апкаст Записей
Интересную особенность записей обнаружил Фил Хаак. Вы не можете сделать апкаст, как для класса. Допустим, у нас есть следующие записи.
Базовая (она же 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)Источник: https://gist.github.com/haacked/b47ed096201a47c9ebceb7397c09d28b
with { Name = "New Name"};
Console.WriteLine(updated);
// Вывод:
// PersonUpdate { Name = New Name }