Skip to content

Instantly share code, notes, and snippets.

@chrispaynter
Created April 26, 2022 08:28
Show Gist options
  • Save chrispaynter/81c8522703c43fe8ea2df6956e6a7b56 to your computer and use it in GitHub Desktop.
Save chrispaynter/81c8522703c43fe8ea2df6956e6a7b56 to your computer and use it in GitHub Desktop.
Strongly type Value Object
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace Test
public abstract class ValueObject<T> where T : ValueObject<T>
{
protected abstract IEnumerable<object> GetEqualityComponents();
public override bool Equals(object? obj)
{
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
var valueObject = (T)obj;
return GetEqualityComponents().SequenceEqual(valueObject.GetEqualityComponents());
}
/// <summary>
/// Refer to this regarding the magic numbers - https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-overriding-gethashcode
/// </summary>
public override int GetHashCode()
{
return GetEqualityComponents()
.Aggregate(1, (current, obj) =>
{
unchecked
{
return current * 23 + (obj?.GetHashCode() ?? 0);
}
});
}
public static bool operator ==(ValueObject<T>? a, ValueObject<T>? b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a.Equals(b);
}
public static bool operator !=(ValueObject<T> a, ValueObject<T> b)
{
return !(a == b);
}
}
public class ValueObjectTests
{
private readonly FavouriteColours myFavouriteColours = new("Me", new[] {"blue", "green"});
private readonly FavouriteColours myFavouriteColoursDuplicated = new("Me", new[] {"blue", "green"});
private readonly FavouriteColours yourFavouriteColours = new("You", new[] {"yellow", "green"});
private readonly FavouriteNumbers myFavouriteNumbers = new("Me", new[] {5, 7, 45});
[Fact]
public void Equal_ChrisFavColoursDuplicated_True()
{
Assert.True(myFavouriteColours == myFavouriteColoursDuplicated);
Assert.True(myFavouriteColours.Equals(myFavouriteColoursDuplicated));
}
[Fact]
public void Equal_ChrisAndMaxFavColours_False()
{
Assert.False(myFavouriteColours == yourFavouriteColours);
Assert.False(myFavouriteColours.Equals(yourFavouriteColours));
}
[Fact]
public void Equal_DifferentTypes_CannotBeCompared()
{
// Assert.False(myFavouriteColours == myFavouriteNumbers);
}
}
public class FavouriteNumbers : ValueObject<FavouriteNumbers>
{
public FavouriteNumbers(string name, IEnumerable<int> numbers)
{
Name = name;
Numbers = numbers;
}
public string Name { get; }
public IEnumerable<int> Numbers { get; }
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Name;
foreach (var number in Numbers)
{
yield return number;
}
}
}
public class FavouriteColours : ValueObject<FavouriteColours>
{
public FavouriteColours(string name, IEnumerable<string> colours)
{
Name = name;
Colours = colours;
}
public string Name { get;}
public IEnumerable<string> Colours { get; }
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Name;
foreach (var colour in Colours)
{
yield return colour;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment