Records code-gen
This is the first-pass release of the LanguageExt.CodeGen
feature for generating record types. This means there's no need to derive from Record<TYPE>
any more, and also allows records to be structs, which is a real bonus.
To create a new record, simply attach the [Record]
attribute to a partial class
or a partial struct
:
[Record]
public partial struct Person
{
public readonly string Forename;
public readonly string Surname;
}
You may also use properties:
[Record]
public partial struct Person
{
public string Forename { get; }
public string Surname { get; }
}
As well as computed properties:
[Record]
public partial struct Person
{
public string Forename { get; }
public string Surname { get; }
public string FullName => $"{Forename} {Surname}";
}
The features of the generated record are:
- Auto constructor provision
- Auto deconstructor provision
- Structural equality (with equality operators also)
- Structural ordering (with ordering operators also)
GetHashCode
provision- Serialisation
- Sensible default
ToString
implementation With
method for immutable transformationLens
fields for composing nested immutable type transformation
Coming soon (for both records and unions) is the ability to provide class-instances to override the default behaviour of equality, ordering, hash-code generation, and constructor validation.
The generated code looks like this:
[System.Serializable]
public partial struct Person : System.IEquatable<Person>, System.IComparable<Person>, System.IComparable, System.Runtime.Serialization.ISerializable
{
public Person(string Forename, string Surname)
{
this.Forename = Forename;
this.Surname = Surname;
}
public void Deconstruct(out string Forename, out string Surname)
{
Forename = this.Forename;
Surname = this.Surname;
}
public Person(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
this.Forename = (string)info.GetValue("Forename", typeof(string));
this.Surname = (string)info.GetValue("Surname", typeof(string));
}
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
info.AddValue("Forename", this.Forename);
info.AddValue("Surname", this.Surname);
}
public static bool operator ==(Person x, Person y) => x.Equals(y);
public static bool operator !=(Person x, Person y) => !(x == y);
public static bool operator>(Person x, Person y) => x.CompareTo(y) > 0;
public static bool operator <(Person x, Person y) => x.CompareTo(y) < 0;
public static bool operator >=(Person x, Person y) => x.CompareTo(y) >= 0;
public static bool operator <=(Person x, Person y) => x.CompareTo(y) <= 0;
public bool Equals(Person other)
{
if (LanguageExt.Prelude.isnull(other))
return false;
if (!default(LanguageExt.ClassInstances.EqDefault<string>).Equals(this.Forename, other.Forename))
return false;
if (!default(LanguageExt.ClassInstances.EqDefault<string>).Equals(this.Surname, other.Surname))
return false;
return true;
}
public override bool Equals(object obj) => obj is Person tobj && Equals(tobj);
public int CompareTo(object obj) => obj is Person p ? CompareTo(p) : 1;
public int CompareTo(Person other)
{
if (LanguageExt.Prelude.isnull(other))
return 1;
int cmp = 0;
cmp = default(LanguageExt.ClassInstances.OrdDefault<string>).Compare(this.Forename, other.Forename);
if (cmp != 0)
return cmp;
cmp = default(LanguageExt.ClassInstances.OrdDefault<string>).Compare(this.Surname, other.Surname);
if (cmp != 0)
return cmp;
return 0;
}
public override int GetHashCode()
{
const int fnvOffsetBasis = -2128831035;
const int fnvPrime = 16777619;
int state = fnvOffsetBasis;
unchecked
{
state = (default(LanguageExt.ClassInstances.EqDefault<string>).GetHashCode(this.Forename) ^ state) * fnvPrime;
state = (default(LanguageExt.ClassInstances.EqDefault<string>).GetHashCode(this.Surname) ^ state) * fnvPrime;
}
return state;
}
public override string ToString()
{
var sb = new System.Text.StringBuilder();
sb.Append("Person(");
sb.Append(LanguageExt.Prelude.isnull(Forename) ? $"Forename: [null]" : $"Forename: {Forename}");
sb.Append($", ");
sb.Append(LanguageExt.Prelude.isnull(Surname) ? $"Surname: [null]" : $"Surname: {Surname}");
sb.Append(")");
return sb.ToString();
}
public Person With(string Forename = null, string Surname = null) => new Person(Forename ?? this.Forename, Surname ?? this.Surname);
public static readonly Lens<Person, string> forename = Lens<Person, string>.New(_x => _x.Forename, _x => _y => _y.With(Forename: _x));
public static readonly Lens<Person, string> surname = Lens<Person, string>.New(_x => _x.Surname, _x => _y => _y.With(Surname: _x));
}