diff --git a/Projects/UOContent.Tests/Tests/Engines/AdvancedSearch/AdvancedSearchUtilitiesTests.cs b/Projects/UOContent.Tests/Tests/Engines/AdvancedSearch/AdvancedSearchUtilitiesTests.cs index 412e5c1e0..030f3f573 100644 --- a/Projects/UOContent.Tests/Tests/Engines/AdvancedSearch/AdvancedSearchUtilitiesTests.cs +++ b/Projects/UOContent.Tests/Tests/Engines/AdvancedSearch/AdvancedSearchUtilitiesTests.cs @@ -54,4 +54,16 @@ public class AdvancedSearchUtilitiesTests var result = AdvancedSearchUtilities.EvaluateBoolean(expr, leaf => leaf == "T"); Assert.Equal(expected, result); } + + [Fact] + public void CompareValues_ReferenceType_EqualityByString_NoThrow() + { + // A reference-typed property (e.g. RootParent name-ish) compared with "=" should not throw, + // and ordering operators must return false rather than throwing. + var ex = Record.Exception(() => + { + Assert.False(AdvancedSearchUtilities.CompareValues(typeof(object), new object(), "whatever", ">")); + }); + Assert.Null(ex); + } } diff --git a/Projects/UOContent/Engines/Advanced Search/AdvancedSearchUtilities.cs b/Projects/UOContent/Engines/Advanced Search/AdvancedSearchUtilities.cs index 16355a249..44a694ef1 100644 --- a/Projects/UOContent/Engines/Advanced Search/AdvancedSearchUtilities.cs +++ b/Projects/UOContent/Engines/Advanced Search/AdvancedSearchUtilities.cs @@ -240,17 +240,38 @@ public static class AdvancedSearchUtilities _ => false }; - public static bool CompareReference(T propertyValue, T parsedValue, ReadOnlySpan operatorSpan) => - operatorSpan switch + public static bool CompareReference(T propertyValue, T parsedValue, ReadOnlySpan operatorSpan) + { + switch (operatorSpan) { - "=" or "==" => propertyValue.Equals(parsedValue), - "!" or "!=" => !propertyValue.Equals(parsedValue), - ">" => Comparer.Default.Compare(propertyValue, parsedValue) > 0, - "<" => Comparer.Default.Compare(propertyValue, parsedValue) < 0, - ">=" => Comparer.Default.Compare(propertyValue, parsedValue) >= 0, - "<=" => Comparer.Default.Compare(propertyValue, parsedValue) <= 0, - _ => false - }; + case "=": + case "==": return Equals(propertyValue, parsedValue); + case "!": + case "!=": return !Equals(propertyValue, parsedValue); + } + + if (propertyValue is IComparable cmp && parsedValue != null) + { + try + { + var c = cmp.CompareTo(parsedValue); + return operatorSpan switch + { + ">" => c > 0, + "<" => c < 0, + ">=" => c >= 0, + "<=" => c <= 0, + _ => false + }; + } + catch + { + return false; + } + } + + return false; + } public static T ParseValue(ReadOnlySpan valuePart) {