Skip to content

Commit

Permalink
Merge pull request #552 from dbuckin1/SeparateComparableTypes
Browse files Browse the repository at this point in the history
Separate comparable types
  • Loading branch information
vkhorikov authored Aug 29, 2024
2 parents 3663a94 + a30d003 commit 298d914
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 64 deletions.
4 changes: 2 additions & 2 deletions CSharpFunctionalExtensions.Tests/EntityTests/BasicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public MyDerivedEntity(long id)
}
}

public class MyId : ValueObject
public class MyId : ComparableValueObject
{
public string Value1 { get; }
public Guid Value2 { get; }
Expand All @@ -151,7 +151,7 @@ public MyId(string value1, Guid value2)
Value2 = value2;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Value1;
yield return Value2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public StringVO(string value)
{
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Value.ToLower();
}
Expand Down
128 changes: 109 additions & 19 deletions CSharpFunctionalExtensions.Tests/ValueObjectTests/BasicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,37 @@ public void It_is_possible_to_override_default_equality_comparison_behavior()
money1.Equals(money2).Should().BeTrue();
money1.GetHashCode().Equals(money2.GetHashCode()).Should().BeTrue();
}

[Fact]
public void It_is_possible_to_override_default_equality_comparison_behavior_for_comparable()
{
var money1 = new ComparableMoney("usd", 2.2222m);
var money2 = new ComparableMoney("USD", 2.22m);

money1.Equals(money2).Should().BeTrue();
money1.GetHashCode().Equals(money2.GetHashCode()).Should().BeTrue();
}

[Fact]
public void Comparing_value_objects_of_different_types_returns_false()
public void Equality_of_value_objects_of_different_types_returns_false()
{
var vo1 = new VO1("1");
var vo2 = new VO2("1");

vo1.Equals(vo2).Should().BeFalse();
}

[Fact]
public void Equality_of_comparable_value_objects_of_different_types_returns_false()
{
var vo1 = new VO1Comparable("1");
var vo2 = new VO2Comparable("1");

vo1.Equals(vo2).Should().BeFalse();
}

[Fact]
public void Comparing_simple_value_objects_of_different_values_returns_false()
public void Equality_of_simple_value_objects_of_different_values_returns_false()
{
var emailAddress1 = new EmailAddress("[email protected]");
var emailAddress2 = new EmailAddress("[email protected]");
Expand All @@ -66,7 +85,7 @@ public void Comparing_simple_value_objects_of_different_values_returns_false()
}

[Fact]
public void Comparing_simple_value_objects_of_different_types_returns_false()
public void Equality_of_simple_value_objects_of_different_types_returns_false()
{
var emailAddress1 = new EmailAddress("[email protected]");
var emailAddress2 = new EmailAddress2("[email protected]");
Expand All @@ -75,7 +94,7 @@ public void Comparing_simple_value_objects_of_different_types_returns_false()
}

[Fact]
public void Comparing_value_objects_with_different_collections_returns_false()
public void Equality_of_value_objects_with_different_collections_returns_false()
{
var vo1 = new VOWithCollection("one", "two");
var vo2 = new VOWithCollection("one", "three");
Expand All @@ -86,9 +105,22 @@ public void Comparing_value_objects_with_different_collections_returns_false()
result1.Should().BeFalse();
result2.Should().BeFalse();
}

[Fact]
public void Equality_of_comparable_value_objects_with_different_collections_returns_false()
{
var vo1 = new ComparableVOWithCollection("one", "two");
var vo2 = new ComparableVOWithCollection("one", "three");

bool result1 = vo1.Equals(vo2);
bool result2 = vo2.Equals(vo1);

result1.Should().BeFalse();
result2.Should().BeFalse();
}

[Fact]
public void Comparing_value_objects_with_collections_of_different_size_returns_false()
public void Equality_of_value_objects_with_collections_of_different_size_returns_false()
{
var vo1 = new VOWithCollection("one", "two");
var vo2 = new VOWithCollection("one", "two", "three");
Expand All @@ -100,6 +132,19 @@ public void Comparing_value_objects_with_collections_of_different_size_returns_f
result2.Should().BeFalse();
}

[Fact]
public void Equality_of_comparable_value_objects_with_collections_of_different_size_returns_false()
{
var vo1 = new ComparableVOWithCollection("one", "two");
var vo2 = new ComparableVOWithCollection("one", "two", "three");

bool result1 = vo1.Equals(vo2);
bool result2 = vo2.Equals(vo1);

result1.Should().BeFalse();
result2.Should().BeFalse();
}

private class VOWithCollection : ValueObject
{
readonly string[] _components;
Expand All @@ -109,7 +154,22 @@ public VOWithCollection(params string[] components)
_components = components;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<object> GetEqualityComponents()
{
return _components;
}
}

private class ComparableVOWithCollection : ComparableValueObject
{
readonly string[] _components;

public ComparableVOWithCollection(params string[] components)
{
_components = components;
}

protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
return _components;
}
Expand All @@ -124,7 +184,22 @@ public VO1(string value)
Value = value;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Value;
}
}

public class VO1Comparable : ComparableValueObject
{
public string Value { get; }

public VO1Comparable(string value)
{
Value = value;
}

protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Value;
}
Expand All @@ -139,7 +214,22 @@ public VO2(string value)
Value = value;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Value;
}
}

public class VO2Comparable : ComparableValueObject
{
public string Value { get; }

public VO2Comparable(string value)
{
Value = value;
}

protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Value;
}
Expand All @@ -156,28 +246,28 @@ public Money(string currency, decimal amount)
Amount = amount;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Currency.ToUpper();
yield return Math.Round(Amount, 2);
}
}

public class Address2 : ValueObject
public class ComparableMoney : ComparableValueObject
{
public string Street { get; }
public string City { get; }
public string Currency { get; }
public decimal Amount { get; }

public Address2(string street, string city)
public ComparableMoney(string currency, decimal amount)
{
Street = street;
City = city;
Currency = currency;
Amount = amount;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Street;
yield return City;
yield return Currency.ToUpper();
yield return Math.Round(Amount, 2);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public void Can_compare_value_objects_with_different_types()
result1.Should().Be(-result2);
}

private class VOWithCollection : ValueObject
private class VOWithCollection : ComparableValueObject
{
readonly string[] _components;

Expand All @@ -132,7 +132,7 @@ public VOWithCollection(params string[] components)
_components = components;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return _components.Length;
foreach (string component in _components)
Expand All @@ -142,7 +142,7 @@ protected override IEnumerable<IComparable> GetEqualityComponents()
}
}

private class VOWithObjectProperty : ValueObject
private class VOWithObjectProperty : ComparableValueObject
{
public object SomeProperty { get; }

Expand All @@ -151,13 +151,13 @@ public VOWithObjectProperty(object someProperty)
SomeProperty = someProperty;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return SomeProperty.GetHashCode();
}
}

private class Name : ValueObject
private class Name : ComparableValueObject
{
public string First { get; }
public string Last { get; }
Expand All @@ -170,7 +170,7 @@ public Name(string first, string last, NameSuffix suffix)
Suffix = suffix;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return First;
yield return Last;
Expand All @@ -186,7 +186,7 @@ public NameSuffix(int value)
{
}
}

private class VOIntType: SimpleValueObject<int>
{
public VOIntType(int value) : base(value)
Expand Down
41 changes: 41 additions & 0 deletions CSharpFunctionalExtensions/ValueObject/ComparableValueObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace CSharpFunctionalExtensions
{
[Serializable]
public abstract class ComparableValueObject : ValueObject, IComparable, IComparable<ComparableValueObject>
{
protected abstract IEnumerable<IComparable> GetComparableEqualityComponents();

protected sealed override IEnumerable<object> GetEqualityComponents() => GetComparableEqualityComponents();

public virtual int CompareTo(ComparableValueObject other)
{
if (other is null)
return 1;

if (ReferenceEquals(this, other))
return 0;

Type thisType = GetUnproxiedType(this);
Type otherType = GetUnproxiedType(other);
if (thisType != otherType)
return string.Compare($"{thisType}", $"{otherType}", StringComparison.Ordinal);

return
GetComparableEqualityComponents().Zip(
other.GetComparableEqualityComponents(),
(left, right) =>
left?.CompareTo(right) ?? (right is null ? 0 : -1))
.FirstOrDefault(cmp => cmp != 0);
}

public virtual int CompareTo(object other)
{
return CompareTo(other as ComparableValueObject);
}
}
}
8 changes: 4 additions & 4 deletions CSharpFunctionalExtensions/ValueObject/EnumValueObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace CSharpFunctionalExtensions
{
public abstract class EnumValueObject<TEnumeration, TId> : ValueObject
public abstract class EnumValueObject<TEnumeration, TId> : ComparableValueObject
where TEnumeration : EnumValueObject<TEnumeration, TId>
where TId : struct, IComparable
{
Expand Down Expand Up @@ -111,7 +111,7 @@ public static Maybe<TEnumeration> FromName(string name)

public override string ToString() => Name;

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Id;
}
Expand All @@ -128,7 +128,7 @@ private static TEnumeration[] GetEnumerations()
}
}

public abstract class EnumValueObject<TEnumeration> : ValueObject
public abstract class EnumValueObject<TEnumeration> : ComparableValueObject
where TEnumeration : EnumValueObject<TEnumeration>
{
private int? _cachedHashCode;
Expand Down Expand Up @@ -224,7 +224,7 @@ public static Maybe<TEnumeration> FromId(string id)

public override string ToString() => Id;

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Id;
}
Expand Down
4 changes: 2 additions & 2 deletions CSharpFunctionalExtensions/ValueObject/SimpleValueObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace CSharpFunctionalExtensions
{
[Serializable]
public abstract class SimpleValueObject<T> : ValueObject
public abstract class SimpleValueObject<T> : ComparableValueObject
where T : IComparable
{
public T Value { get; }
Expand All @@ -14,7 +14,7 @@ protected SimpleValueObject(T value)
Value = value;
}

protected override IEnumerable<IComparable> GetEqualityComponents()
protected override IEnumerable<IComparable> GetComparableEqualityComponents()
{
yield return Value;
}
Expand Down
Loading

0 comments on commit 298d914

Please sign in to comment.