Skip to content

Instantly share code, notes, and snippets.

@CyrusNajmabadi
Last active March 20, 2020 04:36
Show Gist options
  • Save CyrusNajmabadi/3b4a3c12160389c71419d8e502800499 to your computer and use it in GitHub Desktop.
Save CyrusNajmabadi/3b4a3c12160389c71419d8e502800499 to your computer and use it in GitHub Desktop.
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