Remute C# library to create new immutable object applying lambda expressions to the existing immutable object.
For example define immutable class:
public class Employee
{
public string FirstName { get; }
public string LastName { get; }
public Employee(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}
Apply modification:
var remute = new Remute();
var expected = new Employee("John", "Doe");
var actual = remute.With(expected, x => x.FirstName, "Foo");
Generic method With
returns new object where first name is updated:
Assert.AreNotSame(expected.FirstName, actual.FirstName);
Assert.AreSame(expected.LastName, actual.LastName);
Remute works with immutable nested object structures (including C# 9 records).
Define few more immutable classes:
public class Department
{
public string Title { get; }
public Employee Manager { get; }
public Department(string title, Employee manager)
{
Title = title;
Manager = manager;
}
}
public class Organization
{
public string Name { get; }
public Department DevelopmentDepartment { get; }
public Organization(string name, Department developmentDepartment)
{
Name = name;
DevelopmentDepartment = developmentDepartment;
}
}
Remute first name of the manager of the development department:
var expected =
new Organization("Organization",
new Department("Development Department",
new Employee("John", "Doe")));
var actual = remute.With(expected, x => x.DevelopmentDepartment.Manager.FirstName, "Foo");
Actual object has updated references for DevelopmentDepartment
, Manager
and FirstName
.
All other object references (like Organization.Name
, Department.Title
and Employee.LastName
) remain the same.
Assert.AreNotSame(expected, actual);
Assert.AreNotSame(expected.DevelopmentDepartment, actual.DevelopmentDepartment);
Assert.AreNotSame(expected.DevelopmentDepartment.Manager, actual.DevelopmentDepartment.Manager);
Assert.AreSame(expected.Name, actual.Name);
Assert.AreSame(expected.DevelopmentDepartment.Title, expected.DevelopmentDepartment.Title);
By default Remute expects immutable type to have single constructor with parameters matching property names (case-insensetive).
Use ActivationConfiguration
to change this default behaviour. Check issue for more details.
var config = new ActivationConfiguration()
.Configure<User>(x => new User(x.FirstName, x.LastName));
var remute = new Remute(config);
There is an extension method enabling chained modifications on any object.
using Remutable.Extensions;
...
var employee = new Employee(Guid.NewGuid(), "Joe", "Doe");
var actual = employee
.Remute(x => x.FirstName, "Foo")
.Remute(x => x.LastName, "Bar");
Assert.AreEqual("Foo", actual.FirstName);
Assert.AreEqual("Bar", actual.LastName);
Remute does not use reflection / Activator.CreateInstance for object creation. Instead cached lambda expressions are used that demonstrates great performance.
Remute is available as .Net Standard assembly via Nuget
dotnet add package Remute
or
Install-Package Remute