Reputation: 1860
Is it possible to use the with
keyword to create a new instance of nested records with a different value for the nested property - both cases: simple property and collection? Let's see an example:
class Program
{
static void Main(string[] args)
{
var company = new Company(
Name: "Company1",
Branch: new Branch(
Location: "Krakow",
Employees: new[]
{
new Employee("Robert")
}));
Console.WriteLine(company);
}
}
internal record Company(string Name, Branch Branch);
internal record Branch(string Location, IEnumerable<Employee> Employees);
internal record Employee(string FirstName);
In the above example I want to create a new record, but with changed values of the branch location ("Krakow"
) and employee name ("Robert"
). How can I do this most effectively?
Upvotes: 7
Views: 4317
Reputation: 106
You can use LeviySoft.Visor to avoid awkwardness of nested withs:
[Optics(withNested: true)]
internal partial record Company(string Name, Branch Branch);
[Optics(withNested: true)]
internal partial record Branch(string Location, IEnumerable<Employee> Employees);
[Optics]
internal partial record Employee(string FirstName);
var original = new Company(...)
var updated = Company.FocusBranch.LocationLens.Set("Warshaw")(original)
As for the IEnumerable's - you can implement your own IProperty for the IEnumerables taking this as example. Please note that using non-immutable collection interfaces breaks by-value comparison of records (it's the reason why I did not implemented IProperty for IEnumerable)
Upvotes: 0
Reputation: 151690
You can nest your with
expressions:
var clone = company with {
Name = "Company2",
Branch = company.Branch with {
Location = "Warshaw",
Employees = new[]
{
company.Branch.Employees.First() with
{
FirstName = "Bob"
}
}}};
Console.WriteLine(clone);
foreach (var e in clone.Branch.Employees)
{
Console.WriteLine(e);
}
Upvotes: 10