Last active
March 31, 2020 17:32
-
-
Save HaloFour/bccd57c5e4f3261862e04404ce45909e to your computer and use it in GitHub Desktop.
Test inheritance with struct builders
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
/* | |
public record class Person { | |
public required int ID { get; init; } | |
public string FirstName { get; init; } | |
public string LastName { get; init; } | |
Person { | |
if (ID < 0) throw new ArgumentOutOfRangeException(nameof(ID)); | |
} | |
} | |
public record class Student : Person { | |
public required double Gpa { get; init; } | |
Student { | |
// just an example, I understand it's possible for GPAs to exceed this range | |
if (Gpa < 0.0 || Gpa > 4.0) throw new ArgumentOutOfRangeException(nameof(Gpa)); | |
} | |
} | |
*/ | |
using System; | |
public class Person { | |
public int ID { get; } | |
public string FirstName { get; } | |
public string LastName { get; } | |
public Person(Builder builder) : this(null, builder) { } | |
protected Person(Person prototype, Builder builder) { | |
if (prototype != null) { | |
ID = builder.IDSet ? builder.ID : prototype.ID; | |
FirstName = builder.FirstNameSet ? builder.FirstName : prototype.FirstName; | |
LastName = builder.LastNameSet ? builder.LastName : prototype.LastName; | |
} | |
else { | |
if (!builder.IDSet) throw new InvalidOperationException(); | |
ID = builder.ID; | |
FirstName = builder.FirstName; | |
LastName = builder.LastName; | |
} | |
Validate(ID, FirstName, LastName); | |
} | |
private void Validate(int ID, string FirstName, string LastName) { | |
if (ID < 0) throw new ArgumentOutOfRangeException(nameof(ID)); | |
} | |
public static Builder NewBuilder() => default; | |
public virtual Person With(Builder builder) { | |
return new Person(this, builder); | |
} | |
public struct Builder { | |
private byte _set; | |
private int _id; | |
private string _firstName; | |
private string _lastName; | |
public int ID { | |
get => _id; | |
set { | |
_id = value; | |
_set |= 1; | |
} | |
} | |
public string FirstName { | |
get => _firstName; | |
set { | |
_firstName = value; | |
_set |= 2; | |
} | |
} | |
public string LastName { | |
get => _lastName; | |
set { | |
_lastName = value; | |
_set |= 4; | |
} | |
} | |
public bool IDSet => (_set & 1) == 1; | |
public bool FirstNameSet => (_set & 2) == 2; | |
public bool LastNameSet => (_set & 4) == 4; | |
} | |
} | |
public class Student : Person { | |
public double Gpa { get; } | |
public Student(Builder builder) : this(null, builder) { } | |
protected Student(Student prototype, Builder builder) : base(prototype, builder.Parent) { | |
if (prototype != null) { | |
Gpa = builder.GpaSet ? builder.Gpa : prototype.Gpa; | |
} | |
else { | |
if (!builder.GpaSet) throw new InvalidOperationException(); | |
Gpa = builder.Gpa; | |
} | |
Validate(Gpa); | |
} | |
private void Validate(int ID, string FirstName, string LastName, double Gpa) { | |
// just an example, I understand it's possible for GPAs to exceed this range | |
if (Gpa < 0.0 || Gpa > 4.0) throw new ArgumentOutOfRangeException(nameof(Gpa)); | |
} | |
public override Person With(Person.Builder builder) { | |
return new Student(this, new Builder() { Parent = builder }); | |
} | |
public virtual Student With(Student.Builder builder) { | |
return new Student(this, builder); | |
} | |
public new struct Builder { | |
private Person.Builder _parentBuilder; | |
private byte _set; | |
private double _gpa; | |
public Person.Builder Parent { | |
get => _parentBuilder; | |
set => _parentBuilder = value; | |
} | |
public int ID { | |
get => _parentBuilder.ID; | |
set { | |
var temp = _parentBuilder; | |
temp.ID = value; | |
_parentBuilder = temp; | |
} | |
} | |
public string FirstName { | |
get => _parentBuilder.FirstName; | |
set { | |
var temp = _parentBuilder; | |
temp.FirstName = value; | |
_parentBuilder = temp; | |
} | |
} | |
public string LastName { | |
get => _parentBuilder.LastName; | |
set { | |
var temp = _parentBuilder; | |
temp.LastName = value; | |
_parentBuilder = temp; | |
} | |
} | |
public double Gpa { | |
get => _gpa; | |
set { | |
_gpa = value; | |
_set |= 1; | |
} | |
} | |
public bool IDSet => _parentBuilder.IDSet; | |
public bool FirstNameSet => _parentBuilder.FirstNameSet; | |
public bool LastNameSet => _parentBuilder.LastNameSet; | |
public bool GpaSet => (_set & 1) == 1; | |
} | |
} |
Author
HaloFour
commented
Feb 11, 2020
•
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment