Implement IComparable<Duration> for the Duration type (C#)

Note that unlike Timestamp, this does *not* also overload comparison
operators. Adding a `==` overload now would be a breaking change (as
it would change the meaning of existing code from a reference
comparison to a value comparison), and implementing `<`, `<=`, `>=`
and `>` without implementing `==` would be odd.

Implementing `IComparable<T>` makes sorting much easier, however.

Fixes #7628
pull/10441/head
Jon Skeet 2 years ago
parent 3c32c05e13
commit 8fd097b0da
  1. 33
      csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs
  2. 23
      csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs

@ -128,5 +128,38 @@ namespace Google.Protobuf.WellKnownTypes
var duration = new Duration { Seconds = 1, Nanos = -1 };
Assert.AreEqual("{ \"@warning\": \"Invalid Duration\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString());
}
[Test]
public void Comparability()
{
Duration[] durationsInExpectedSortOrder =
{
null,
new Duration { Seconds = -10, Nanos = -10 },
new Duration { Seconds = -10, Nanos = -1 },
new Duration { Seconds = -1, Nanos = -10 },
new Duration { Seconds = -1, Nanos = -1 },
new Duration(),
new Duration { Seconds = 1, Nanos = 1 },
new Duration { Seconds = 1, Nanos = 10 },
new Duration { Seconds = 10, Nanos = 1 },
new Duration { Seconds = 10, Nanos = 10 }
};
for (int i = 0; i < durationsInExpectedSortOrder.Length; i++)
{
var target = durationsInExpectedSortOrder[i];
if (target is null)
{
continue;
}
for (int j = 0; j < durationsInExpectedSortOrder.Length; j++)
{
var expectedResult = Math.Sign(i - j);
var actualResult = target.CompareTo(durationsInExpectedSortOrder[j]);
Assert.AreEqual(expectedResult, actualResult);
}
}
}
}
}

@ -38,7 +38,7 @@ namespace Google.Protobuf.WellKnownTypes
{
// Manually-written partial class for the Duration well-known type,
// providing a conversion to TimeSpan and convenience operators.
public partial class Duration : ICustomDiagnosticMessage
public partial class Duration : ICustomDiagnosticMessage, IComparable<Duration>
{
/// <summary>
/// The number of nanoseconds in a second.
@ -266,5 +266,26 @@ namespace Google.Protobuf.WellKnownTypes
}
}
}
/// <summary>
/// Given another duration, returns 0 if the durations are equivalent, -1 if this duration is shorter than the other, and 1 otherwise.
/// </summary>
/// <remarks>
/// This method expects that both durations are normalized; that is, that the values of <see cref="Seconds"/>
/// and <see cref="Nanos"/> are within the documented bounds.
/// If either value is not normalized, the results of this method are unspecified.
/// </remarks>
/// <param name="other">The duration to compare with this object.</param>
/// <returns>An integer indicating whether this duration is shorter or longer than <paramref name="other"/>.</returns>
public int CompareTo(Duration other)
{
return other == null ? 1
: Seconds < other.Seconds ? -1
: Seconds > other.Seconds ? 1
: Nanos < other.Nanos ? -1
: Nanos > other.Nanos ? 1
: 0;
}
}
}

Loading…
Cancel
Save