-
Notifications
You must be signed in to change notification settings - Fork 309
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #552 from dbuckin1/SeparateComparableTypes
Separate comparable types
- Loading branch information
Showing
8 changed files
with
168 additions
and
64 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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]"); | ||
|
@@ -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]"); | ||
|
@@ -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"); | ||
|
@@ -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"); | ||
|
@@ -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; | ||
|
@@ -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; | ||
} | ||
|
@@ -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; | ||
} | ||
|
@@ -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; | ||
} | ||
|
@@ -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); | ||
} | ||
} | ||
|
||
|
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
41 changes: 41 additions & 0 deletions
41
CSharpFunctionalExtensions/ValueObject/ComparableValueObject.cs
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
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); | ||
} | ||
} | ||
} |
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
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
Oops, something went wrong.