Skip to content

Commit b5eb9d5

Browse files
committed
✨ Add back IEquatable with strict equality
Fixes #1017 Reverted removing IEquatable and changed the implementation to strict equality and improved the xmldocs a bit. Reverts commit f3c7e25. "🔥 Remove IEquatable<T> and equality operators/methods"
1 parent 23f8eaf commit b5eb9d5

File tree

236 files changed

+11572
-354
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

236 files changed

+11572
-354
lines changed

CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ namespace UnitsNet
7777
Writer.W("IDecimalQuantity, ");
7878
}
7979

80-
Writer.WL($"IComparable, IComparable<{_quantity.Name}>, IConvertible, IFormattable");
80+
Writer.WL($"IEquatable<{_quantity.Name}>, IComparable, IComparable<{_quantity.Name}>, IConvertible, IFormattable");
8181
Writer.WL($@"
8282
{{
8383
/// <summary>
@@ -752,7 +752,33 @@ private void GenerateEqualityAndComparison()
752752
return left.Value > right.ToUnit(left.Unit).Value;
753753
}}
754754
755-
/// <inheritdoc />
755+
/// <summary>Returns true if both <see cref=""Value"" /> and <see cref=""Unit"" /> are exactly equal for both quantities.</summary>
756+
/// <remarks>Consider using <see cref=""Equals({_quantity.Name}, double, ComparisonType)""/> for comparing floating point values with rounding error tolerances.</remarks>
757+
public static bool operator ==({_quantity.Name} left, {_quantity.Name} right)
758+
{{
759+
return left.Equals(right);
760+
}}
761+
762+
/// <summary>Returns true if either <see cref=""Value"" /> or <see cref=""Unit"" /> are not exactly equal for both quantities.</summary>
763+
/// <remarks>Consider using <see cref=""Equals({_quantity.Name}, double, ComparisonType)""/> for comparing floating point values with rounding error tolerances.</remarks>
764+
public static bool operator !=({_quantity.Name} left, {_quantity.Name} right)
765+
{{
766+
return !(left == right);
767+
}}
768+
769+
/// <summary>Compares the current <see cref=""{_quantity.Name}""/> with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other when converted to the same unit.</summary>
770+
/// <param name=""obj"">An object to compare with this instance.</param>
771+
/// <exception cref=""T:System.ArgumentException"">
772+
/// <paramref name=""obj"" /> is not the same type as this instance.
773+
/// </exception>
774+
/// <returns>A value that indicates the relative order of the quantities being compared. The return value has these meanings:
775+
/// <list type=""table"">
776+
/// <listheader><term> Value</term><description> Meaning</description></listheader>
777+
/// <item><term> Less than zero</term><description> This instance precedes <paramref name=""obj"" /> in the sort order.</description></item>
778+
/// <item><term> Zero</term><description> This instance occurs in the same position in the sort order as <paramref name=""obj"" />.</description></item>
779+
/// <item><term> Greater than zero</term><description> This instance follows <paramref name=""obj"" /> in the sort order.</description></item>
780+
/// </list>
781+
/// </returns>
756782
public int CompareTo(object obj)
757783
{{
758784
if (obj is null) throw new ArgumentNullException(nameof(obj));
@@ -761,12 +787,40 @@ public int CompareTo(object obj)
761787
return CompareTo(obj{_quantity.Name});
762788
}}
763789
764-
/// <inheritdoc />
790+
/// <summary>Compares the current <see cref=""{_quantity.Name}""/> with another <see cref=""{_quantity.Name}""/> and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other when converted to the same unit.</summary>
791+
/// <param name=""other"">A quantity to compare with this instance.</param>
792+
/// <returns>A value that indicates the relative order of the quantities being compared. The return value has these meanings:
793+
/// <list type=""table"">
794+
/// <listheader><term> Value</term><description> Meaning</description></listheader>
795+
/// <item><term> Less than zero</term><description> This instance precedes <paramref name=""other"" /> in the sort order.</description></item>
796+
/// <item><term> Zero</term><description> This instance occurs in the same position in the sort order as <paramref name=""other"" />.</description></item>
797+
/// <item><term> Greater than zero</term><description> This instance follows <paramref name=""other"" /> in the sort order.</description></item>
798+
/// </list>
799+
/// </returns>
765800
public int CompareTo({_quantity.Name} other)
766801
{{
767802
return _value.CompareTo(other.ToUnit(this.Unit).Value);
768803
}}
769804
805+
/// <inheritdoc />
806+
/// <summary>Returns true if either <see cref=""Value"" /> or <see cref=""Unit"" /> are not exactly equal for both quantities.</summary>
807+
/// <remarks>Consider using <see cref=""Equals({_quantity.Name}, double, ComparisonType)""/> for comparing floating point values with rounding error tolerances.</remarks>
808+
public override bool Equals(object obj)
809+
{{
810+
if(obj is null || !(obj is {_quantity.Name} obj{_quantity.Name}))
811+
return false;
812+
813+
return Equals(obj{_quantity.Name});
814+
}}
815+
816+
/// <inheritdoc />
817+
/// <summary>Returns true if either <see cref=""Value"" /> or <see cref=""Unit"" /> are not exactly equal for both quantities.</summary>
818+
/// <remarks>Consider using <see cref=""Equals({_quantity.Name}, double, ComparisonType)""/> for comparing floating point values with rounding error tolerances.</remarks>
819+
public bool Equals({_quantity.Name} other)
820+
{{
821+
return new {{ Value, Unit }}.Equals(new {{ other.Value, other.Unit }});
822+
}}
823+
770824
/// <summary>
771825
/// <para>
772826
/// Compare equality to another {_quantity.Name} within the given absolute or relative tolerance.

CodeGen/Generators/UnitsNetGen/UnitTestBaseClassGenerator.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,33 @@ internal class UnitTestBaseClassGenerator : GeneratorBase
4545
/// </summary>
4646
private readonly string _numberSuffix;
4747

48+
/// <summary>
49+
/// Other unit, if more than one unit exists for quantity, otherwise same as <see cref="_baseUnit"/>.
50+
/// </summary>
51+
private readonly Unit _otherOrBaseUnit;
52+
53+
/// <summary>
54+
/// Example: "LengthUnit.Centimeter".
55+
/// </summary>
56+
private readonly string _otherOrBaseUnitFullName;
57+
4858
public UnitTestBaseClassGenerator(Quantity quantity)
4959
{
5060
_quantity = quantity;
5161
_baseUnit = quantity.Units.FirstOrDefault(u => u.SingularName == _quantity.BaseUnit) ??
5262
throw new ArgumentException($"No unit found with SingularName equal to BaseUnit [{_quantity.BaseUnit}]. This unit must be defined.",
5363
nameof(quantity));
64+
5465
_unitEnumName = $"{quantity.Name}Unit";
66+
5567
_baseUnitEnglishAbbreviation = GetEnglishAbbreviation(_baseUnit);
5668
_baseUnitFullName = $"{_unitEnumName}.{_baseUnit.SingularName}";
5769
_numberSuffix = quantity.ValueType == "decimal" ? "m" : "";
70+
71+
// Try to pick another unit, or fall back to base unit if only a single unit.
72+
_otherOrBaseUnit = quantity.Units.Where(u => u != _baseUnit).DefaultIfEmpty(_baseUnit).First();
73+
_otherOrBaseUnitFullName = $"{_unitEnumName}.{_otherOrBaseUnit.SingularName}";
74+
5875
}
5976

6077
private string GetUnitFullName(Unit unit) => $"{_unitEnumName}.{unit.SingularName}";
@@ -483,6 +500,52 @@ public void CompareToThrowsOnNull()
483500
Assert.Throws<ArgumentNullException>(() => {baseUnitVariableName}.CompareTo(null));
484501
}}
485502
503+
[Theory]
504+
[InlineData(1, {_baseUnitFullName}, 1, {_baseUnitFullName}, true)] // Same value and unit.
505+
[InlineData(1, {_baseUnitFullName}, 2, {_baseUnitFullName}, false)] // Different value.
506+
[InlineData(2, {_baseUnitFullName}, 1, {_otherOrBaseUnitFullName}, false)] // Different value and unit.");
507+
if (_baseUnit != _otherOrBaseUnit)
508+
{
509+
Writer.WL($@"
510+
[InlineData(1, {_baseUnitFullName}, 1, {_otherOrBaseUnitFullName}, false)] // Different unit.");
511+
}
512+
Writer.WL($@"
513+
public void Equals_ReturnsTrue_IfValueAndUnitAreEqual({_quantity.ValueType} valueA, {_unitEnumName} unitA, {_quantity.ValueType} valueB, {_unitEnumName} unitB, bool expectEqual)
514+
{{
515+
var a = new {_quantity.Name}(valueA, unitA);
516+
var b = new {_quantity.Name}(valueB, unitB);
517+
518+
// Operator overloads.
519+
Assert.Equal(expectEqual, a == b);
520+
Assert.Equal(expectEqual, b == a);
521+
Assert.Equal(!expectEqual, a != b);
522+
Assert.Equal(!expectEqual, b != a);
523+
524+
// IEquatable<T>
525+
Assert.Equal(expectEqual, a.Equals(b));
526+
Assert.Equal(expectEqual, b.Equals(a));
527+
528+
// IEquatable
529+
Assert.Equal(expectEqual, a.Equals((object)b));
530+
Assert.Equal(expectEqual, b.Equals((object)a));
531+
}}
532+
533+
[Fact]
534+
public void Equals_Null_ReturnsFalse()
535+
{{
536+
var a = {_quantity.Name}.Zero;
537+
538+
Assert.False(a.Equals((object)null));
539+
540+
// ""The result of the expression is always 'false'...""
541+
#pragma warning disable CS8073
542+
Assert.False(a == null);
543+
Assert.False(null == a);
544+
Assert.True(a != null);
545+
Assert.True(null != a);
546+
#pragma warning restore CS8073
547+
}}
548+
486549
[Fact]
487550
public void Equals_RelativeTolerance_IsImplemented()
488551
{{

UnitsNet.Tests/GeneratedCode/TestsBase/AccelerationTestsBase.g.cs

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnitsNet.Tests/GeneratedCode/TestsBase/AmountOfSubstanceTestsBase.g.cs

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnitsNet.Tests/GeneratedCode/TestsBase/AmplitudeRatioTestsBase.g.cs

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnitsNet.Tests/GeneratedCode/TestsBase/AngleTestsBase.g.cs

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)