Last active
March 20, 2020 04:36
-
-
Save CyrusNajmabadi/3b4a3c12160389c71419d8e502800499 to your computer and use it in GitHub Desktop.
This file contains 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
using System; | |
public class Person | |
{ | |
public int Age { get; } | |
public string Name { get; } | |
public Person(int age, string name) | |
: this(null, new Builder { Age = age, Name = name }) | |
{ | |
} | |
protected Person(Person prototype, in Builder builder) | |
{ | |
if (prototype != null) | |
{ | |
Age = builder.HasAge ? builder.Age : prototype.Age; | |
Name = builder.HasName ? builder.Name : prototype.Name; | |
} | |
else | |
{ | |
Age = builder.Age; | |
Name = builder.Name; | |
} | |
// extra constructor logic/validation. | |
} | |
// Can have custom logic in here to return 'this' if builder wouldn't | |
// change what we already are. | |
public virtual Person With(in Builder builder) | |
=> new Person(this, builder); | |
public ref struct Builder | |
{ | |
private byte _set; | |
private int _age; | |
private string _name; | |
public int Age | |
{ | |
get => _age; | |
set { _age = value; _set |= 1; } | |
} | |
public string Name | |
{ | |
get => _name; | |
set { _name = value; _set |= 2; } | |
} | |
public bool HasAge => (_set & 1) == 1; | |
public bool HasName => (_set & 2) == 2; | |
} | |
} | |
public class Student : Person | |
{ | |
public double Gpa { get; } | |
public Student(int age, string name, double gpa) | |
: this(null, new Builder { Age = age, Name = name, Gpa = gpa }) | |
{ | |
} | |
protected Student(Student prototype, in Builder builder) | |
: base(prototype, builder.Parent) | |
{ | |
if (prototype != null) | |
{ | |
Gpa = builder.HasGpa ? builder.Gpa : prototype.Gpa; | |
} | |
else | |
{ | |
Gpa = builder.Gpa; | |
} | |
// extra constructor logic/validation. | |
} | |
public override Person With(in Person.Builder builder) | |
=> With(new Builder { Parent = builder }); | |
public virtual Student With(in Builder builder) | |
=> new Student(this, builder); | |
public new ref struct Builder | |
{ | |
public Person.Builder Parent; | |
private byte _set; | |
private double _gpa; | |
public int Age | |
{ | |
get => Parent.Age; | |
set => Parent.Age = value; | |
} | |
public string Name | |
{ | |
get => Parent.Name; | |
set => Parent.Name = value; | |
} | |
public double Gpa | |
{ | |
get => _gpa; | |
set { _gpa = value; _set |= 1; } | |
} | |
public bool HasAge => Parent.HasAge; | |
public bool HasName => Parent.HasName; | |
public bool HasGpa => (_set & 1) == 1; | |
} | |
} | |
class Usage | |
{ | |
static void Main() | |
{ | |
var madsStudent = new Student(age: 39, name: "mads", gpa: 4.0); | |
var cyrusStudent = madsStudent.With(new Student.Builder | |
{ | |
Name = "cyrus", | |
}); | |
var madsPerson = (Person)madsStudent; | |
var dustinPerson = madsPerson.With(new Person.Builder { Name = "dustin " }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment