From 4fe1b2a1c8eb601feb329ab1780849c57249b3fe Mon Sep 17 00:00:00 2001 From: Ewout Kramer Date: Fri, 17 Jan 2025 13:42:37 +0100 Subject: [PATCH] Replaced Result with normal TryXXX pattern. --- src/Hl7.Fhir.Base/ElementModel/Types/Any.cs | 2 +- .../ElementModel/Types/Boolean.cs | 4 +- src/Hl7.Fhir.Base/ElementModel/Types/Code.cs | 2 + .../ElementModel/Types/Concept.cs | 2 + src/Hl7.Fhir.Base/ElementModel/Types/Date.cs | 11 +-- .../ElementModel/Types/DateTime.cs | 11 +-- .../ElementModel/Types/Decimal.cs | 4 +- src/Hl7.Fhir.Base/ElementModel/Types/Long.cs | 79 ++++++------------- .../ElementModel/Types/Quantity.cs | 41 ++++------ src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs | 18 ++--- .../ElementModel/Types/String.cs | 28 +++---- src/Hl7.Fhir.Base/ElementModel/Types/Time.cs | 36 ++++----- .../FhirPath/Functions/EqualityOperators.cs | 2 +- src/Hl7.Fhir.Base/Model/Base64Binary.cs | 33 ++++---- .../ElementModel/EquivalenceTests.cs | 8 +- 15 files changed, 107 insertions(+), 174 deletions(-) diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs index 6b67438d4a..436df86b1f 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Any.cs @@ -154,7 +154,7 @@ public static bool TryConvert(object? value, [NotNullWhen(true)] out Any? primit } // some utility methods shared by the subclasses - protected static ArgumentException NotSameTypeComparison(object me, object? them) => + protected static InvalidOperationException NotSameTypeComparison(object me, object? them) => new($"Cannot compare {me} (of type {me.GetType()}) to {them} (of type {them?.GetType()}), because the types differ."); protected static TOut RunCast(Any value) => diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs index 20194d34c3..cf4d8fe828 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Boolean.cs @@ -20,7 +20,7 @@ public class Boolean(bool value) : Any, ICqlEquatable, ICqlConvertible public const string TRUE_LITERAL = "true"; public const string FALSE_LITERAL = "false"; - public Boolean() : this(default) { } + public Boolean() : this(false) { } public bool Value { get; } = value; @@ -43,7 +43,7 @@ public static bool TryParse(string representation, [NotNullWhen(true)] out Boole } else { - value = default; + value = null; return false; } } diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs index 5b7cb36287..c94df0c81a 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Code.cs @@ -45,4 +45,6 @@ public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) } public override string ToString() => $"{Value}@{System} " + Display; + + // Does not support equality, equivalence and ordering in the CQL sense, so no explicit implementations of these interfaces } \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs index 91d3c98453..8283c94fba 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Concept.cs @@ -36,4 +36,6 @@ public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) } public override string ToString() => string.Join(", ", Codes) + (Display != null ? $" \"{Display}\"" : ""); + + // Does not support equality, equivalence and ordering in the CQL sense, so no explicit implementations of these interfaces } \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs index 6f2846afa9..7c3ad105e1 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Date.cs @@ -196,14 +196,11 @@ private static Date add(Date dateValue, decimal value, string unit) public bool TryEquals(Any other, [NotNullWhen(true)] out bool? result) { - if (other is Date && TryCompareTo(other, out var comparison)) - { - result = comparison == 0; - return true; - } + result = other is Date + ? TryCompareTo(other, out var comparison) ? comparison == 0 : null + : false; - result = null; - return false; + return result is not null; } public static bool operator ==(Date a, Date b) => Equals(a, b); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs index 2e1e85aec9..cdcdf1e429 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/DateTime.cs @@ -246,14 +246,11 @@ public override bool Equals(object? obj) => obj is Any other && TryEquals(other, public bool TryEquals(Any other, [NotNullWhen(true)] out bool? result) { - if (other is DateTime && TryCompareTo(other, out var comparison)) - { - result = comparison == 0; - return true; - } + result = other is DateTime + ? TryCompareTo(other, out var comparison) ? comparison == 0 : null + : false; - result = null; - return false; + return result is not null; } public static bool operator ==(DateTime a, DateTime b) => Equals(a, b); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs index 224b954bb0..219d0fbb79 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Decimal.cs @@ -16,7 +16,7 @@ namespace Hl7.Fhir.ElementModel.Types; -public class Decimal(decimal value = default) : Any, IComparable, ICqlEquatable, ICqlOrderable +public class Decimal(decimal value = 0) : Any, IComparable, ICqlEquatable, ICqlOrderable { public decimal Value { get; } = value; @@ -31,7 +31,7 @@ public static bool TryParse(string representation, [NotNullWhen(true)] out Decim { if (representation == null) throw new ArgumentNullException(nameof(representation)); - value = default; + value = null; if (FORBIDDEN_DECIMAL_PREFIXES.Any(representation.StartsWith) || representation.EndsWith(".")) return false; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs index eefeb16a1a..fa9b6d8229 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Long.cs @@ -68,64 +68,37 @@ public int CompareTo(object? obj) public static implicit operator long(Long i) => i.Value; public static explicit operator Long(long i) => new (i); - public static implicit operator Decimal(Long i) => new (i.Value); - public static implicit operator Quantity(Long i) => new (i.Value); - - public static explicit operator Boolean(Long l) => - l.Value switch - { - 1 => Boolean.True, - 0 => Boolean.False, - _ => throw new InvalidCastException($"Cannot cast Long value {l} to Boolean.") - }; - - public static implicit operator String(Long l) => new(l.ToString()); - - public static explicit operator Integer(Long l) => - l.Value is >= int.MinValue and <= int.MaxValue - ? new Integer((int)l.Value) - : throw new InvalidCastException($"Cannot cast Long value {l} to Integer, it is too large."); + public static explicit operator Decimal(Long i) => RunCast(i); + public static explicit operator Quantity(Long i) => RunCast(i); + public static explicit operator Boolean(Long l) => RunCast(l); + public static explicit operator String(Long l) => RunCast(l); + public static explicit operator Integer(Long l) => RunCast(l); public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) { + result = null; + if (to == typeof(Long)) - { result = this; - return true; - } - - if (to == typeof(Integer)) - { - result = (Integer)this; - return true; - } - - if (to == typeof(Decimal)) - { - result = (Decimal)this; - return true; - } - - if (to == typeof(Quantity)) - { - result = (Quantity)this; - return true; - } - - if (to == typeof(Boolean)) - { - result = (Boolean)this; - return true; - } - - if (to == typeof(String)) - { - result = (String)this; - return true; - } - - result = default; - return false; + else if (to == typeof(Integer)) + result = Value is >= int.MinValue and <= int.MaxValue + ? new Integer((int)Value) + : null; + else if (to == typeof(Decimal)) + result = new Decimal(Value); + else if (to == typeof(Quantity)) + result = new Quantity(Value); + else if (to == typeof(Boolean)) + result = Value switch + { + 1 => Boolean.True, + 0 => Boolean.False, + _ => null + }; + else if (to == typeof(String)) + result = new String(ToString()); + + return result is not null; } bool? ICqlEquatable.IsEqualTo(Any? other) => other is not null ? Equals(other) : null; diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs index 78c2878252..6c97ca4ba7 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs @@ -176,14 +176,11 @@ public bool Equals(Any other, QuantityComparison comparisonType) => /// calendar durations and definite quantity durations above seconds is determined by the public bool TryEquals(Any other, QuantityComparison comparisonType, [NotNullWhen(true)] out bool? result) { - if (other is Quantity && TryCompareTo(other, comparisonType, out var comparison)) - { - result = comparison == 0; - return true; - } + result = other is Quantity + ? TryCompareTo(other, comparisonType, out var comparison) ? comparison == 0 : null + : false; - result = null; - return false; + return result is not null; } public static bool operator ==(Quantity a, Quantity b) => a.CompareTo(b) == 0; @@ -224,11 +221,7 @@ public bool TryCompareTo(Any? other, QuantityComparison comparisonType, [NotNull return true; } - if (other is not Quantity otherQ) - { - result = null; - return false; - } + if (other is not Quantity otherQ) throw NotSameTypeComparison(this, other); if (IsDuration && otherQ.IsDuration) { @@ -277,7 +270,7 @@ Quantity normalizeToUcum(Quantity orig) _ => throw new InvalidOperationException($"Unit '{orig.Unit}' is not a known calendar duration.") }; - return new(orig.Value, ucumUnit, QuantityUnitSystem.UCUM); + return new Quantity(orig.Value, ucumUnit, QuantityUnitSystem.UCUM); } } @@ -309,25 +302,21 @@ bool ICqlEquatable.IsEquivalentTo(Any? other) => other is not null && TryEquals(other, CQL_EQUIVALENCE_COMPARISON, out var result) && result.Value; int? ICqlOrderable.CompareTo(Any? other) => - other is not null && TryCompareTo(other, out var result) ? result : null; + other is not null && TryCompareTo(other, out var result) + ? result + : null; - public static explicit operator String(Quantity q) => new(q.ToString()); + public static explicit operator String(Quantity q) => RunCast(q); public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) { + result = null; + if(to == typeof(Quantity)) - { result = this; - return true; - } - - if (to == typeof(String)) - { - result = (String)this; - return true; - } + else if (to == typeof(String)) + result = new String(ToString()); - result = default; - return false; + return result is not null; } } \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs index ad88225d9a..6b90f03a25 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Ratio.cs @@ -43,24 +43,18 @@ public static bool TryParse(string representation, [NotNullWhen(true)] out Ratio public override int GetHashCode() => (Numerator, Denominator).GetHashCode(); public override string ToString() => $"{Numerator}:{Denominator}"; - public static explicit operator String(Ratio r) => new(r.ToString()); + public static explicit operator String(Ratio r) => RunCast(r); public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) { + result = null; + if(to == typeof(Ratio)) - { result = this; - return true; - } - - if (to == typeof(String)) - { - result = (String)this; - return true; - } + else if (to == typeof(String)) + result = new String(ToString()); - result = default; - return false; + return result is not null; } public static bool operator ==(Ratio left, Ratio right) => left.Equals(right); diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs index 15c8b5c015..c4cd7dc7bc 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/String.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/String.cs @@ -8,7 +8,6 @@ #nullable enable -using Hl7.FhirPath.Sprache; using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -93,35 +92,26 @@ public int CompareTo(object? obj) public override string ToString() => Value; public static implicit operator string(String s) => s.Value; - public static implicit operator String(string s) => new(s); - - public static explicit operator Boolean(String s) => - s.TryConvertTo(out var result) - ? result - : throw new InvalidCastException($"Cannot cast String value {s} to Boolean."); + public static explicit operator String(string s) => new(s); + public static explicit operator Boolean(String s) => RunCast(s); public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) { + result = null; + if(to == typeof(String)) - { result = this; - return true; - } - - if (to == typeof(Boolean)) - { - var boolValue = Value.ToLower() switch + else if (to == typeof(Boolean)) + result = Value.ToLower() switch { "true" or "t" or "yes" or "y" or "1" or "1.0" => Boolean.True, "false" or "f" or "no" or "n" or "0" or "0.0" => Boolean.False, _ => null }; + else + _ = TryParseToAny(Value, to, out result); - result = boolValue; - return result is not null; - } - - return TryParseToAny(Value, to, out result); + return result is not null; } private static T convertTo(String s) where T:Any => diff --git a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs index 6ab8b75069..6399ae3029 100644 --- a/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs +++ b/src/Hl7.Fhir.Base/ElementModel/Types/Time.cs @@ -148,14 +148,12 @@ private static bool tryParse(string representation, out Time? value) public bool TryEquals(Any other, [NotNullWhen(true)] out bool? result) { - if (other is Time && TryCompareTo(other, out var comparison)) - { - result = comparison == 0; - return true; - } + result = other is Time + ? TryCompareTo(other, out var comparison) ? comparison == 0 : null + : false; + + return result is not null; - result = null; - return false; } public static bool operator ==(Time a, Time b) => Equals(a, b); @@ -229,31 +227,25 @@ public override string ToString() return _value.ToString(formatString, CultureInfo.InvariantCulture); } - public static explicit operator Time(DateTimeOffset dto) => FromDateTimeOffset(dto); - public static implicit operator String(Time dt) => new(dt.ToString()); - - bool? ICqlEquatable.IsEqualTo(Any? other) => other is not null && TryEquals(other, out var result) ? result : null; + bool? ICqlEquatable.IsEqualTo(Any? other) => other is not null && TryEquals(other, out var result) ? result : null; // Note that, in contrast to equals, this will return false if operators cannot be compared (as described by the spec) bool ICqlEquatable.IsEquivalentTo(Any? other) => other is not null && TryEquals(other, out var result) && result.Value; int? ICqlOrderable.CompareTo(Any? other) => other is not null && TryCompareTo(other, out var result) ? result : null; + public static explicit operator Time(DateTimeOffset dto) => FromDateTimeOffset(dto); + public static explicit operator String(Time dt) => RunCast(dt); + public override bool TryConvertTo(Type to, [NotNullWhen(true)] out Any? result) { + result = null; + if(to == typeof(Time)) - { result = this; - return true; - } + else if(to == typeof(String)) + result = new String(ToString()); - if(to == typeof(String)) - { - result = (String)this; - return true; - } - - result = default; - return false; + return result is not null; } } \ No newline at end of file diff --git a/src/Hl7.Fhir.Base/FhirPath/Functions/EqualityOperators.cs b/src/Hl7.Fhir.Base/FhirPath/Functions/EqualityOperators.cs index e427799309..edcc323763 100644 --- a/src/Hl7.Fhir.Base/FhirPath/Functions/EqualityOperators.cs +++ b/src/Hl7.Fhir.Base/FhirPath/Functions/EqualityOperators.cs @@ -207,7 +207,7 @@ public static bool IsEquivalentTo(P.Any? left, P.Any? right) - public static bool? Compare(P.Any left, P.Any right, string op) + public static bool? Compare(P.Any? left, P.Any? right, string op) { // If one or both of the arguments is an empty collection, a comparison operator will return an empty collection. // (though we might handle this more generally with the null-propagating functionality of the compiler diff --git a/src/Hl7.Fhir.Base/Model/Base64Binary.cs b/src/Hl7.Fhir.Base/Model/Base64Binary.cs index 8f8fd24790..70818df47a 100644 --- a/src/Hl7.Fhir.Base/Model/Base64Binary.cs +++ b/src/Hl7.Fhir.Base/Model/Base64Binary.cs @@ -32,26 +32,23 @@ POSSIBILITY OF SUCH DAMAGE. #nullable enable -namespace Hl7.Fhir.Model +namespace Hl7.Fhir.Model; + +public partial class Base64Binary { - public partial class Base64Binary + /// + /// Checks whether the given literal is correctly formatted. + /// + public static bool IsValidValue(string value) { - /// - /// Checks whether the given literal is correctly formatted. - /// - public static bool IsValidValue(string value) + try + { + _ = Convert.FromBase64String(value); + return true; + } + catch { - try - { - _ = Convert.FromBase64String(value); - return true; - } - catch - { - return false; - } + return false; } } -} - -#nullable restore \ No newline at end of file +} \ No newline at end of file diff --git a/src/Hl7.Fhir.Support.Tests/ElementModel/EquivalenceTests.cs b/src/Hl7.Fhir.Support.Tests/ElementModel/EquivalenceTests.cs index 01466fd272..62268e8f5d 100644 --- a/src/Hl7.Fhir.Support.Tests/ElementModel/EquivalenceTests.cs +++ b/src/Hl7.Fhir.Support.Tests/ElementModel/EquivalenceTests.cs @@ -51,8 +51,8 @@ public void TestEqualityIncompatibleTypes() Assert.IsFalse(EqualityOperators.IsEquivalentTo(new Quantity(4.0m, "kg"), new Code("http://nu.nl", "R"))); Assert.IsFalse(EqualityOperators.IsEquivalentTo(new Integer(0), new String("hi!"))); - Assert.ThrowsException(() => EqualityOperators.Compare(new Quantity(4.0m, "kg"), new Code("http://nu.nl", "R"), "=")); - Assert.ThrowsException(() => EqualityOperators.Compare(new Integer(0), new String("hi!"), ">=")); + Assert.ThrowsException(() => EqualityOperators.Compare(new Quantity(4.0m, "kg"), new Code("http://nu.nl", "R"), "=")); + Assert.ThrowsException(() => EqualityOperators.Compare(new Integer(0), new String("hi!"), ">=")); } internal static IEnumerable equalityTestcases() => @@ -354,7 +354,7 @@ internal static IEnumerable orderingTestcases() => [DynamicData(nameof(orderingTestcases), DynamicDataSourceType.Method)] public void OrderingTest(object a, object b, int? s) { - if (s == 1 || s == -1) + if (s is 1 or -1) { doOrderingTest(a, b, s); doOrderingTest(b, a, -s); @@ -377,4 +377,4 @@ private static void doOrderingTest(object a, object b, int? s) } } } -} +} \ No newline at end of file