I did something that does what you have been asking lately (using T4 templates), so this is absolutely possible:
https://github.com/xaviergonz/T4Immutable
For example, given this:
[ImmutableClass(Options = ImmutableClassOptions.IncludeOperatorEquals)] class Person { private const int AgeDefaultValue = 18; public string FirstName { get; } public string LastName { get; } public int Age { get; } [ComputedProperty] public string FullName { get { return FirstName + " " + LastName; } } }
It automatically generates the following for you in a separate file of a partial file:
- A constructor such as public Person (string firstName, string lastName, int age = 18) that initialize the values.
- Working implementations for Equals (other object) and Equals (Person other). It will also add the IEquatable interface for you. Implementation work for operator == and operator! =
- Working implementation of GetHashCode () Better than ToString () with an output, for example, "Person {FirstName = John, LastName = Doe, Age = 21}"
- The Person With (...) method, which can be used to create a new immutable clone with 0 or more changed properties (for example, var janeDoe = johnDoe.With (firstName: "Jane", age: 20)
Therefore, it will generate this (excluding some redundant attributes):
using System; partial class Person : IEquatable<Person> { public Person(string firstName, string lastName, int age = 18) { this.FirstName = firstName; this.LastName = lastName; this.Age = age; _ImmutableHashCode = new { this.FirstName, this.LastName, this.Age }.GetHashCode(); } private bool ImmutableEquals(Person obj) { if (ReferenceEquals(this, obj)) return true; if (ReferenceEquals(obj, null)) return false; return T4Immutable.Helpers.AreEqual(this.FirstName, obj.FirstName) && T4Immutable.Helpers.AreEqual(this.LastName, obj.LastName) && T4Immutable.Helpers.AreEqual(this.Age, obj.Age); } public override bool Equals(object obj) { return ImmutableEquals(obj as Person); } public bool Equals(Person obj) { return ImmutableEquals(obj); } public static bool operator ==(Person a, Person b) { return T4Immutable.Helpers.AreEqual(a, b); } public static bool operator !=(Person a, Person b) { return !T4Immutable.Helpers.AreEqual(a, b); } private readonly int _ImmutableHashCode; private int ImmutableGetHashCode() { return _ImmutableHashCode; } public override int GetHashCode() { return ImmutableGetHashCode(); } private string ImmutableToString() { var sb = new System.Text.StringBuilder(); sb.Append(nameof(Person) + " { "); var values = new string[] { nameof(this.FirstName) + "=" + T4Immutable.Helpers.ToString(this.FirstName), nameof(this.LastName) + "=" + T4Immutable.Helpers.ToString(this.LastName), nameof(this.Age) + "=" + T4Immutable.Helpers.ToString(this.Age), }; sb.Append(string.Join(", ", values) + " }"); return sb.ToString(); } public override string ToString() { return ImmutableToString(); } private Person ImmutableWith(T4Immutable.WithParam<string> firstName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<string> lastName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<int> age = default(T4Immutable.WithParam<int>)) { return new Person( !firstName.HasValue ? this.FirstName : firstName.Value, !lastName.HasValue ? this.LastName : lastName.Value, !age.HasValue ? this.Age : age.Value ); } public Person With(T4Immutable.WithParam<string> firstName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<string> lastName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<int> age = default(T4Immutable.WithParam<int>)) { return ImmutableWith(firstName, lastName, age); } }
And there are a few more features as described on the project page.