This is an automated email from the ASF dual-hosted git repository.

paulirwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucenenet.git


The following commit(s) were added to refs/heads/master by this push:
     new 3d489a6d9 Add operator overrides for public IComparable types, #683 
(#1056)
3d489a6d9 is described below

commit 3d489a6d9a86c58ca7940d489bfe75f00962f42f
Author: Paul Irwin <[email protected]>
AuthorDate: Sun Dec 15 08:57:17 2024 -0700

    Add operator overrides for public IComparable types, #683 (#1056)
    
    * Add operator overrides for IComparable types, #683
---
 Lucene.Net.sln.DotSettings                         |  1 +
 src/Lucene.Net.Benchmark/Quality/QualityQuery.cs   | 71 ++++++++++++++++------
 .../VectorHighlight/FieldPhraseList.cs             | 55 ++++++++++++++++-
 .../VectorHighlight/FieldTermStack.cs              | 27 +++++++-
 .../Surround/Query/SimpleTerm.cs                   | 34 ++++++++++-
 src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs         | 36 ++++++++---
 .../Suggest/Fst/FSTCompletion.cs                   | 38 +++++++++++-
 src/Lucene.Net.Suggest/Suggest/Lookup.cs           | 50 ++++++++++++---
 src/Lucene.Net/Index/IndexCommit.cs                | 31 +++++++++-
 src/Lucene.Net/Index/Term.cs                       | 27 +++++++-
 src/Lucene.Net/Util/Automaton/State.cs             | 30 ++++++++-
 src/Lucene.Net/Util/BytesRef.cs                    | 25 ++++++++
 src/Lucene.Net/Util/CharsRef.cs                    | 25 ++++++++
 src/Lucene.Net/Util/IntsRef.cs                     | 25 ++++++++
 src/Lucene.Net/Util/LongsRef.cs                    | 25 ++++++++
 src/Lucene.Net/Util/Mutable/MutableValue.cs        | 33 ++++++++--
 16 files changed, 483 insertions(+), 50 deletions(-)

diff --git a/Lucene.Net.sln.DotSettings b/Lucene.Net.sln.DotSettings
index 6fd109800..dae1019eb 100644
--- a/Lucene.Net.sln.DotSettings
+++ b/Lucene.Net.sln.DotSettings
@@ -1,4 +1,5 @@
 <wpf:ResourceDictionary xml:space="preserve" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"; 
xmlns:s="clr-namespace:System;assembly=mscorlib" 
xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" 
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation";>
        <s:Boolean 
x:Key="/Default/UserDictionary/Words/=Coord/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/UserDictionary/Words/=csharpsquid/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean 
x:Key="/Default/UserDictionary/Words/=LUCENENET/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean 
x:Key="/Default/UserDictionary/Words/=testsettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
\ No newline at end of file
diff --git a/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs 
b/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs
index cc45910d1..28caf01ab 100644
--- a/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs
+++ b/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs
@@ -3,6 +3,7 @@ using J2N.Text;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+#nullable enable
 
 namespace Lucene.Net.Benchmarks.Quality
 {
@@ -28,13 +29,13 @@ namespace Lucene.Net.Benchmarks.Quality
     /// <para/>
     /// The ID allows to map the quality query with its judgements.
     /// <para/>
-    /// The name-value pairs are used by a 
+    /// The name-value pairs are used by a
     /// <see cref="IQualityQueryParser"/>
     /// to create a Lucene <see cref="Search.Query"/>.
     /// <para/>
     /// It is very likely that name-value-pairs would be mapped into fields in 
a Lucene query,
     /// but it is up to the QualityQueryParser how to map - e.g. all values in 
a single field,
-    /// or each pair as its own field, etc., - and this of course must match 
the way the 
+    /// or each pair as its own field, etc., - and this of course must match 
the way the
     /// searched index was constructed.
     /// </summary>
     public class QualityQuery : IComparable<QualityQuery>
@@ -49,8 +50,8 @@ namespace Lucene.Net.Benchmarks.Quality
         /// <param name="nameValPairs">The contents of this quality 
query.</param>
         public QualityQuery(string queryID, IDictionary<string, string> 
nameValPairs)
         {
-            this.queryID = queryID;
-            this.nameValPairs = nameValPairs;
+            this.queryID = queryID ?? throw new 
ArgumentNullException(nameof(queryID));
+            this.nameValPairs = nameValPairs ?? throw new 
ArgumentNullException(nameof(nameValPairs));
         }
 
         /// <summary>
@@ -66,10 +67,9 @@ namespace Lucene.Net.Benchmarks.Quality
         /// </summary>
         /// <param name="name">The name whose value should be returned.</param>
         /// <returns></returns>
-        public virtual string GetValue(string name)
+        public virtual string? GetValue(string name)
         {
-            nameValPairs.TryGetValue(name, out string result);
-            return result;
+            return nameValPairs.TryGetValue(name, out string? result) ? result 
: null;
         }
 
         /// <summary>
@@ -82,22 +82,57 @@ namespace Lucene.Net.Benchmarks.Quality
         /// For a nicer sort of input queries before running them.
         /// Try first as ints, fall back to string if not int.
         /// </summary>
-        /// <param name="other"></param>
-        /// <returns></returns>
-        public virtual int CompareTo(QualityQuery other)
+        /// <param name="other">The other <see cref="QualityQuery"/> to 
compare to.</param>
+        /// <returns>0 if equal, a negative value if smaller, a positive value 
if larger.</returns>
+        public virtual int CompareTo(QualityQuery? other)
         {
-            try
+            if (other is null)
             {
-                // compare as ints when ids ints
-                int n = int.Parse(queryID, CultureInfo.InvariantCulture);
-                int nOther = int.Parse(other.queryID, 
CultureInfo.InvariantCulture);
-                return n - nOther;
+                return 1;
             }
-            catch (Exception e) when (e.IsNumberFormatException())
+
+            if (int.TryParse(queryID, NumberStyles.Integer, 
CultureInfo.InvariantCulture, out int n)
+                && int.TryParse(other.queryID, NumberStyles.Integer, 
CultureInfo.InvariantCulture, out int nOther))
             {
-                // fall back to string comparison
-                return queryID.CompareToOrdinal(other.queryID);
+                return n - nOther;
             }
+
+            // fall back to string comparison
+            return queryID.CompareToOrdinal(other.queryID);
         }
+
+        // LUCENENET specific - provide Equals and GetHashCode due to 
providing operator overrides
+        public override bool Equals(object? obj)
+        {
+            if (obj is null) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+            return queryID == ((QualityQuery)obj).queryID;
+        }
+
+        public override int GetHashCode() => queryID.GetHashCode();
+
+        #region Operator overrides
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(QualityQuery? left, QualityQuery? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(QualityQuery? left, QualityQuery? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(QualityQuery? left, QualityQuery? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(QualityQuery? left, QualityQuery? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(QualityQuery? left, QualityQuery? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(QualityQuery? left, QualityQuery? right)
+            => !(left == right);
+
+        #endregion
     }
 }
diff --git a/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs 
b/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs
index f2f8996ad..7ece6682d 100644
--- a/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs
+++ b/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs
@@ -442,7 +442,7 @@ namespace Lucene.Net.Search.VectorHighlight
 
             public override bool Equals(object obj)
             {
-                if (this == obj)
+                if (ReferenceEquals(this, obj))
                 {
                     return true;
                 }
@@ -470,6 +470,31 @@ namespace Lucene.Net.Search.VectorHighlight
                 return true;
             }
 
+            #region Operator overrides
+#nullable enable
+            // LUCENENET specific - per csharpsquid:S1210, IComparable<T> 
should override comparison operators
+
+            public static bool operator <(WeightedPhraseInfo? left, 
WeightedPhraseInfo? right)
+                => left is null ? right is not null : left.CompareTo(right) < 
0;
+
+            public static bool operator <=(WeightedPhraseInfo? left, 
WeightedPhraseInfo? right)
+                => left is null || left.CompareTo(right) <= 0;
+
+            public static bool operator >(WeightedPhraseInfo? left, 
WeightedPhraseInfo? right)
+                => left is not null && left.CompareTo(right) > 0;
+
+            public static bool operator >=(WeightedPhraseInfo? left, 
WeightedPhraseInfo? right)
+                => left is null ? right is null : left.CompareTo(right) >= 0;
+
+            public static bool operator ==(WeightedPhraseInfo? left, 
WeightedPhraseInfo? right)
+                => left?.Equals(right) ?? right is null;
+
+            public static bool operator !=(WeightedPhraseInfo? left, 
WeightedPhraseInfo? right)
+                => !(left == right);
+
+#nullable restore
+            #endregion
+
             /// <summary>
             /// Term offsets (start + end)
             /// </summary>
@@ -512,7 +537,7 @@ namespace Lucene.Net.Search.VectorHighlight
 
                 public override bool Equals(object obj)
                 {
-                    if (this == obj)
+                    if (ReferenceEquals(this, obj))
                     {
                         return true;
                     }
@@ -535,12 +560,38 @@ namespace Lucene.Net.Search.VectorHighlight
                     }
                     return true;
                 }
+
                 public override string ToString()
                 {
                     StringBuilder sb = new StringBuilder();
                     
sb.Append('(').Append(startOffset).Append(',').Append(endOffset).Append(')');
                     return sb.ToString();
                 }
+
+                #region Operator overrides
+#nullable enable
+                // LUCENENET specific - per csharpsquid:S1210, IComparable<T> 
should override comparison operators
+
+                public static bool operator <(Toffs? left, Toffs? right)
+                    => left is null ? right is not null : 
left.CompareTo(right) < 0;
+
+                public static bool operator <=(Toffs? left, Toffs? right)
+                    => left is null || left.CompareTo(right) <= 0;
+
+                public static bool operator >(Toffs? left, Toffs? right)
+                    => left is not null && left.CompareTo(right) > 0;
+
+                public static bool operator >=(Toffs? left, Toffs? right)
+                    => left is null ? right is null : left.CompareTo(right) >= 
0;
+
+                public static bool operator ==(Toffs? left, Toffs? right)
+                    => left?.Equals(right) ?? right is null;
+
+                public static bool operator !=(Toffs? left, Toffs? right)
+                    => !(left == right);
+
+#nullable restore
+                #endregion
             }
         }
     }
diff --git a/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs 
b/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs
index 5c909b109..b8230ba33 100644
--- a/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs
+++ b/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs
@@ -265,7 +265,7 @@ namespace Lucene.Net.Search.VectorHighlight
 
             public override bool Equals(object obj)
             {
-                if (this == obj)
+                if (ReferenceEquals(this, obj))
                 {
                     return true;
                 }
@@ -284,6 +284,31 @@ namespace Lucene.Net.Search.VectorHighlight
                 }
                 return true;
             }
+
+            #region Operator overrides
+#nullable enable
+            // LUCENENET specific - per csharpsquid:S1210, IComparable<T> 
should override comparison operators
+
+            public static bool operator <(TermInfo? left, TermInfo? right)
+                => left is null ? right is not null : left.CompareTo(right) < 
0;
+
+            public static bool operator <=(TermInfo? left, TermInfo? right)
+                => left is null || left.CompareTo(right) <= 0;
+
+            public static bool operator >(TermInfo? left, TermInfo? right)
+                => left is not null && left.CompareTo(right) > 0;
+
+            public static bool operator >=(TermInfo? left, TermInfo? right)
+                => left is null ? right is null : left.CompareTo(right) >= 0;
+
+            public static bool operator ==(TermInfo? left, TermInfo? right)
+                => left?.Equals(right) ?? right is null;
+
+            public static bool operator !=(TermInfo? left, TermInfo? right)
+                => !(left == right);
+
+#nullable restore
+            #endregion
         }
     }
 }
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs 
b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs
index ad9c6dcad..cf9b006d9 100644
--- a/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs
@@ -2,6 +2,7 @@
 using Lucene.Net.Index;
 using System;
 using System.Text;
+#pragma warning disable CS0660, CS0661 // CompareTo is deprecated, so skipping 
implementing equality members (lucenenet#683)
 
 namespace Lucene.Net.QueryParsers.Surround.Query
 {
@@ -28,8 +29,8 @@ namespace Lucene.Net.QueryParsers.Surround.Query
     public abstract class SimpleTerm : SrndQuery, IDistanceSubQuery, 
IComparable<SimpleTerm>
     {
         protected SimpleTerm(bool quoted) // LUCENENET: CA1012: Abstract types 
should not have constructors (marked protected)
-        { 
-            this.quoted = quoted; 
+        {
+            this.quoted = quoted;
         }
 
         private readonly bool quoted; // LUCENENET: marked readonly
@@ -115,5 +116,34 @@ namespace Lucene.Net.QueryParsers.Surround.Query
         {
             return new SimpleTermRewriteQuery(this, fieldName, qf);
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+        // NOTE: The CompareTo method is marked as obsolete, but we still need 
to implement the comparison operators
+        // since this is public in 4.8. Suppressing the obsolete warning here.
+
+#pragma warning disable CS0618 // Type or member is obsolete
+        public static bool operator <(SimpleTerm? left, SimpleTerm? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(SimpleTerm? left, SimpleTerm? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(SimpleTerm? left, SimpleTerm? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(SimpleTerm? left, SimpleTerm? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+#pragma warning restore CS0618 // Type or member is obsolete
+
+        public static bool operator ==(SimpleTerm? left, SimpleTerm? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(SimpleTerm? left, SimpleTerm? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
 }
diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs 
b/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
index d34214438..9d48a8b57 100644
--- a/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
+++ b/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
@@ -28,13 +28,13 @@ namespace Lucene.Net.Spatial.Prefix.Tree
     /// <summary>
     /// Represents a grid cell. These are not necessarily thread-safe, 
although new
     /// Cell("") (world cell) must be.
-    /// 
+    ///
     /// @lucene.experimental
     /// </summary>
     public abstract class Cell : IComparable<Cell>
     {
         /// <summary>
-        /// LUCENENET specific - we need to set the SpatialPrefixTree before 
calling overridden 
+        /// LUCENENET specific - we need to set the SpatialPrefixTree before 
calling overridden
         /// members of this class, just in case those overridden members 
require it. This is
         /// not possible from the subclass because the constructor of the base 
class runs first.
         /// So we need to move the reference here and also set it before 
running the normal constructor
@@ -90,7 +90,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             {
                 this.token = token.Substring(0, (token.Length - 1) - 0);
                 // LUCENENET specific - calling private instead of virtual to 
avoid initialization issues
-                SetLeafInternal(); 
+                SetLeafInternal();
             }
             if (Level == 0)
             {
@@ -178,8 +178,8 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         public virtual bool IsLeaf => m_leaf;
 
         /// <summary>Note: not supported at level 0.
-        /// 
-        /// NOTE: When overriding this method, be aware that the constructor 
of this class calls 
+        ///
+        /// NOTE: When overriding this method, be aware that the constructor 
of this class calls
         /// a private method and not this virtual method. So if you need to 
override
         /// the behavior during the initialization, call your own private 
method from the constructor
         /// with whatever custom behavior you need.
@@ -232,7 +232,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         //public Cell getParent();
         /// <summary>
         /// Like <see cref="GetSubCells()">GetSubCells()</see> but with the 
results filtered by a shape. If
-        /// that shape is a <see cref="IPoint"/> then it must call 
+        /// that shape is a <see cref="IPoint"/> then it must call
         /// <see cref="GetSubCell(IPoint)"/>. The returned cells
         /// should have <see cref="ShapeRel">ShapeRel</see> set to their 
relation with
         /// <paramref name="shapeFilter"/>. In addition, <see cref="IsLeaf"/>
@@ -337,5 +337,27 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 
         #endregion
 
+        #region Operator overrides
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(Cell? left, Cell? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(Cell? left, Cell? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(Cell? left, Cell? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(Cell? left, Cell? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(Cell? left, Cell? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(Cell? left, Cell? right)
+            => !(left == right);
+
+        #endregion
     }
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs 
b/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs
index a2a4f9038..06587b33c 100644
--- a/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs
+++ b/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs
@@ -46,10 +46,10 @@ namespace Lucene.Net.Search.Suggest.Fst
         {
             /// <summary>
             /// UTF-8 bytes of the suggestion </summary>
-            public BytesRef Utf8 { get; private set; }
+            public BytesRef Utf8 { get; }
             /// <summary>
             /// source bucket (weight) of the suggestion </summary>
-            public int Bucket { get; private set; }
+            public int Bucket { get; }
 
             internal Completion(BytesRef key, int bucket)
             {
@@ -67,6 +67,40 @@ namespace Lucene.Net.Search.Suggest.Fst
             {
                 return this.Utf8.CompareTo(o.Utf8);
             }
+
+            // LUCENENET specific - per CS0660 and CS0661, we need to override 
Equals and GetHashCode
+            // ReSharper disable once BaseObjectEqualsIsObjectEquals
+            // ReSharper disable once RedundantOverriddenMember
+            public override bool Equals(object obj) => base.Equals(obj);
+
+            // ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode
+            // ReSharper disable once RedundantOverriddenMember
+            public override int GetHashCode() => base.GetHashCode();
+
+            #region Operator overrides
+#nullable enable
+            // LUCENENET specific - per csharpsquid:S1210, IComparable<T> 
should override comparison operators
+
+            public static bool operator <(Completion? left, Completion? right)
+                => left is null ? right is not null : left.CompareTo(right) < 
0;
+
+            public static bool operator <=(Completion? left, Completion? right)
+                => left is null || left.CompareTo(right) <= 0;
+
+            public static bool operator >(Completion? left, Completion? right)
+                => left is not null && left.CompareTo(right) > 0;
+
+            public static bool operator >=(Completion? left, Completion? right)
+                => left is null ? right is null : left.CompareTo(right) >= 0;
+
+            public static bool operator ==(Completion? left, Completion? right)
+                => left?.Equals(right) ?? right is null;
+
+            public static bool operator !=(Completion? left, Completion? right)
+                => !(left == right);
+
+#nullable restore
+            #endregion
         }
 
         /// <summary>
diff --git a/src/Lucene.Net.Suggest/Suggest/Lookup.cs 
b/src/Lucene.Net.Suggest/Suggest/Lookup.cs
index a04cb73da..a644eece3 100644
--- a/src/Lucene.Net.Suggest/Suggest/Lookup.cs
+++ b/src/Lucene.Net.Suggest/Suggest/Lookup.cs
@@ -39,25 +39,25 @@ namespace Lucene.Net.Search.Suggest
         {
             /// <summary>
             /// the key's text </summary>
-            public string Key { get; private set; }
+            public string Key { get; }
 
             /// <summary>
             /// Expert: custom Object to hold the result of a
-            /// highlighted suggestion. 
+            /// highlighted suggestion.
             /// </summary>
-            public object HighlightKey { get; private set; }
+            public object HighlightKey { get; }
 
             /// <summary>
             /// the key's weight </summary>
-            public long Value { get; private set; }
+            public long Value { get; }
 
             /// <summary>
             /// the key's payload (null if not present) </summary>
-            public BytesRef Payload { get; private set; }
+            public BytesRef Payload { get; }
 
             /// <summary>
             /// the key's contexts (null if not present) </summary>
-            public IEnumerable<BytesRef> Contexts { get; private set; }
+            public IEnumerable<BytesRef> Contexts { get; }
 
             /// <summary>
             /// Create a new result from a key+weight pair.
@@ -122,6 +122,38 @@ namespace Lucene.Net.Search.Suggest
             {
                 return CHARSEQUENCE_COMPARER.Compare(Key, o.Key);
             }
+
+            // LUCENENET specific - per CS0660 and CS0661, we need to override 
Equals and GetHashCode
+            // ReSharper disable once BaseObjectEqualsIsObjectEquals
+            // ReSharper disable once RedundantOverriddenMember
+            public override bool Equals(object obj) => base.Equals(obj);
+
+            // ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode
+            // ReSharper disable once RedundantOverriddenMember
+            public override int GetHashCode() => base.GetHashCode();
+
+            #region Operator overrides
+            // LUCENENET specific - per csharpsquid:S1210, IComparable<T> 
should override comparison operators
+
+            public static bool operator <(LookupResult left, LookupResult 
right)
+                => left is null ? right is not null : left.CompareTo(right) < 
0;
+
+            public static bool operator <=(LookupResult left, LookupResult 
right)
+                => left is null || left.CompareTo(right) <= 0;
+
+            public static bool operator >(LookupResult left, LookupResult 
right)
+                => left is not null && left.CompareTo(right) > 0;
+
+            public static bool operator >=(LookupResult left, LookupResult 
right)
+                => left is null ? right is null : left.CompareTo(right) >= 0;
+
+            public static bool operator ==(LookupResult left, LookupResult 
right)
+                => left?.Equals(right) ?? right is null;
+
+            public static bool operator !=(LookupResult left, LookupResult 
right)
+                => !(left == right);
+
+            #endregion
         }
 
         /// <summary>
@@ -129,7 +161,7 @@ namespace Lucene.Net.Search.Suggest
         /// </summary>
         public static readonly IComparer<string> CHARSEQUENCE_COMPARER = new 
CharSequenceComparer();
 
-        // LUCENENET: It is no longer good practice to use binary 
serialization. 
+        // LUCENENET: It is no longer good practice to use binary 
serialization.
         // See: 
https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568
 #if FEATURE_SERIALIZABLE
         [Serializable]
@@ -201,7 +233,7 @@ namespace Lucene.Net.Search.Suggest
         }
 
         /// <summary>
-        /// Sole constructor. (For invocation by subclass 
+        /// Sole constructor. (For invocation by subclass
         /// constructors, typically implicit.)
         /// </summary>
         protected Lookup() // LUCENENET: CA1012: Abstract types should not 
have constructors (marked protected)
@@ -306,4 +338,4 @@ namespace Lucene.Net.Search.Suggest
         /// <returns> ram size of the lookup implementation in bytes </returns>
         public abstract long GetSizeInBytes();
     }
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Index/IndexCommit.cs 
b/src/Lucene.Net/Index/IndexCommit.cs
index 3caabec52..303aa328e 100644
--- a/src/Lucene.Net/Index/IndexCommit.cs
+++ b/src/Lucene.Net/Index/IndexCommit.cs
@@ -117,8 +117,8 @@ namespace Lucene.Net.Index
         public abstract long Generation { get; }
 
         /// <summary>
-        /// Returns userData, previously passed to 
-        /// <see cref="IndexWriter.SetCommitData(IDictionary{string, 
string})"/>} for this commit.  
+        /// Returns userData, previously passed to
+        /// <see cref="IndexWriter.SetCommitData(IDictionary{string, 
string})"/>} for this commit.
         /// The dictionary is <see cref="string"/> -> <see cref="string"/>.
         /// </summary>
         public abstract IDictionary<string, string> UserData { get; }
@@ -145,5 +145,30 @@ namespace Lucene.Net.Index
                 return 0;
             }
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(IndexCommit? left, IndexCommit? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(IndexCommit? left, IndexCommit? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(IndexCommit? left, IndexCommit? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(IndexCommit? left, IndexCommit? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(IndexCommit? left, IndexCommit? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(IndexCommit? left, IndexCommit? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Index/Term.cs b/src/Lucene.Net/Index/Term.cs
index e7841ca78..6e76a7951 100644
--- a/src/Lucene.Net/Index/Term.cs
+++ b/src/Lucene.Net/Index/Term.cs
@@ -189,5 +189,30 @@ namespace Lucene.Net.Index
         {
             return Field + ":" + Text;
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(Term? left, Term? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(Term? left, Term? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(Term? left, Term? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(Term? left, Term? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(Term? left, Term? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(Term? left, Term? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Util/Automaton/State.cs 
b/src/Lucene.Net/Util/Automaton/State.cs
index 898bdff63..ccc5ca5af 100644
--- a/src/Lucene.Net/Util/Automaton/State.cs
+++ b/src/Lucene.Net/Util/Automaton/State.cs
@@ -360,17 +360,45 @@ namespace Lucene.Net.Util.Automaton
             return s.id - id;
         }
 
-        // LUCENENET NOTE: DO NOT IMPLEMENT Equals()!!!
+        // LUCENENET NOTE: DO NOT IMPLEMENT Equals() with structural 
equality!!!
         // Although it doesn't match GetHashCode(), checking for
         // reference equality is by design.
         // Implementing Equals() causes difficult to diagnose
         // IndexOutOfRangeExceptions when using FuzzyTermsEnum.
         // See GH-296.
+        // Overriding here to prevent CS0660 warning due to defining the == 
operator.
+        // ReSharper disable once BaseObjectEqualsIsObjectEquals
+        public override bool Equals(object obj) => base.Equals(obj);
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public override int GetHashCode()
         {
             return id;
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(State? left, State? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(State? left, State? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(State? left, State? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(State? left, State? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(State? left, State? right)
+            => left is null ? right is null : ReferenceEquals(left, right);
+
+        public static bool operator !=(State? left, State? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
 }
diff --git a/src/Lucene.Net/Util/BytesRef.cs b/src/Lucene.Net/Util/BytesRef.cs
index b381f31eb..8012c7728 100644
--- a/src/Lucene.Net/Util/BytesRef.cs
+++ b/src/Lucene.Net/Util/BytesRef.cs
@@ -400,6 +400,31 @@ namespace Lucene.Net.Util
             }
             return true;
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(BytesRef? left, BytesRef? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(BytesRef? left, BytesRef? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(BytesRef? left, BytesRef? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(BytesRef? left, BytesRef? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(BytesRef? left, BytesRef? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(BytesRef? left, BytesRef? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
 
     // LUCENENET: It is no longer good practice to use binary serialization.
diff --git a/src/Lucene.Net/Util/CharsRef.cs b/src/Lucene.Net/Util/CharsRef.cs
index 14cc2b1de..48a35debb 100644
--- a/src/Lucene.Net/Util/CharsRef.cs
+++ b/src/Lucene.Net/Util/CharsRef.cs
@@ -443,5 +443,30 @@ namespace Lucene.Net.Util
             }
             return true;
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(CharsRef? left, CharsRef? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(CharsRef? left, CharsRef? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(CharsRef? left, CharsRef? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(CharsRef? left, CharsRef? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(CharsRef? left, CharsRef? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(CharsRef? left, CharsRef? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
 }
diff --git a/src/Lucene.Net/Util/IntsRef.cs b/src/Lucene.Net/Util/IntsRef.cs
index ef90b03e4..901dbcf79 100644
--- a/src/Lucene.Net/Util/IntsRef.cs
+++ b/src/Lucene.Net/Util/IntsRef.cs
@@ -293,5 +293,30 @@ namespace Lucene.Net.Util
             }
             return true;
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(Int32sRef? left, Int32sRef? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(Int32sRef? left, Int32sRef? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(Int32sRef? left, Int32sRef? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(Int32sRef? left, Int32sRef? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(Int32sRef? left, Int32sRef? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(Int32sRef? left, Int32sRef? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
 }
diff --git a/src/Lucene.Net/Util/LongsRef.cs b/src/Lucene.Net/Util/LongsRef.cs
index 94cf2f873..f15578afb 100644
--- a/src/Lucene.Net/Util/LongsRef.cs
+++ b/src/Lucene.Net/Util/LongsRef.cs
@@ -292,5 +292,30 @@ namespace Lucene.Net.Util
             }
             return true;
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(Int64sRef? left, Int64sRef? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(Int64sRef? left, Int64sRef? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(Int64sRef? left, Int64sRef? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(Int64sRef? left, Int64sRef? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(Int64sRef? left, Int64sRef? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(Int64sRef? left, Int64sRef? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
 }
diff --git a/src/Lucene.Net/Util/Mutable/MutableValue.cs 
b/src/Lucene.Net/Util/Mutable/MutableValue.cs
index 183f30e9e..62762057c 100644
--- a/src/Lucene.Net/Util/Mutable/MutableValue.cs
+++ b/src/Lucene.Net/Util/Mutable/MutableValue.cs
@@ -61,8 +61,8 @@ namespace Lucene.Net.Util.Mutable
         }
 
 
-        // LUCENENET specific implementation, for use with 
FunctionFirstPassGroupingCollector 
-        // (note that IComparable<T> does not inherit IComparable, so we need 
to explicitly 
+        // LUCENENET specific implementation, for use with 
FunctionFirstPassGroupingCollector
+        // (note that IComparable<T> does not inherit IComparable, so we need 
to explicitly
         // implement here in order to support IComparable)
         public virtual int CompareTo(object other)
         {
@@ -82,7 +82,7 @@ namespace Lucene.Net.Util.Mutable
 
         public override bool Equals(object other)
         {
-            return (this.GetType() == other.GetType()) && 
this.EqualsSameType(other);
+            return this.GetType() == other?.GetType() && 
this.EqualsSameType(other);
         }
 
         public override abstract int GetHashCode();
@@ -91,5 +91,30 @@ namespace Lucene.Net.Util.Mutable
         {
             return Exists ? ToObject().ToString() : "(null)";
         }
+
+        #region Operator overrides
+#nullable enable
+        // LUCENENET specific - per csharpsquid:S1210, IComparable<T> should 
override comparison operators
+
+        public static bool operator <(MutableValue? left, MutableValue? right)
+            => left is null ? right is not null : left.CompareTo(right) < 0;
+
+        public static bool operator <=(MutableValue? left, MutableValue? right)
+            => left is null || left.CompareTo(right) <= 0;
+
+        public static bool operator >(MutableValue? left, MutableValue? right)
+            => left is not null && left.CompareTo(right) > 0;
+
+        public static bool operator >=(MutableValue? left, MutableValue? right)
+            => left is null ? right is null : left.CompareTo(right) >= 0;
+
+        public static bool operator ==(MutableValue? left, MutableValue? right)
+            => left?.Equals(right) ?? right is null;
+
+        public static bool operator !=(MutableValue? left, MutableValue? right)
+            => !(left == right);
+
+#nullable restore
+        #endregion
     }
-}
\ No newline at end of file
+}


Reply via email to