Last active
April 21, 2022 20:05
-
-
Save haacked/b47ed096201a47c9ebceb7397c09d28b to your computer and use it in GitHub Desktop.
Upcast record without more specific type properties
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Suppose we have the two record types | |
public record Person(int Id) : PersonUpdate() | |
{ | |
}; | |
public record PersonUpdate() | |
{ | |
public string Name {get; init;} | |
//... bunch of other properties. | |
}; | |
// And the following third party API (I don't control it). | |
public interface IApi | |
{ | |
Task<Person> GetPersonAsync(int id); | |
Task UpdatePersonAsync(int id, PersonUpdate personUpdate); // API rejects properties it doesn't expect such as "Id". | |
} | |
// What I want to do is get a `PersonUpdate` an existing `Person` without the `Id` property. | |
// Here's what I tried. | |
var person = await GetPersonAsync(42); | |
var personUpdate = (PersonUpdate)person with {Name: "new name"}; | |
await UpdatePersonAsync(42, personUpdate); // Fails because personUpdate is still a `Person` with the `Id` property of `Person`. | |
// I also tried this. | |
public record PersonUpdate() | |
{ | |
public PersonUpdate(PersonUpdate personUpdate) : base(personUpdate) | |
{ | |
} | |
public string Name {get; init;} | |
//... bunch of other properties. | |
}; | |
var personUpdate = new PersonUpdate(person); // Nothing got copied. |
So it turns out that records have the copy constructor I want, but it's protected
. So the solution was this:
public record PersonUpdate()
{
// Properties
public static PersonUpdate LossyCopy(PersonUpdate personUpdate) => new(personUpdate);
}
So you're calling api like:
await UpdatePersonAsync(PersonUpdate.LossyCopy(person));
?
@sbenzenko exactly, though in practice it might look like this:
var person = await GetPersonAsync(42);
var personUpdate = PersonUpdate.LossyCopy(person) with { Name = "New Name };
await UpdatePersonAsync(42, personUpdate);
That would be how I would change the name of a person.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In case it's useful, LINQPad example when able to adjust serialization for this case: