From a02f039ada2caf7c74876ac49e4d48c65dcaeb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 24 Sep 2025 17:31:05 +0100 Subject: [PATCH] Add collection related interfaces and classes - Add IEnumerable, IEnumerator, IComparer and SZGenericArrayEnumeratorBase. - Add lang version property with 13.0 (required for generic types with ref structs). - Fix some code style issues. - Commented out several comparares classes waiting for need accessment. - Remove unused code. --- nanoFramework.CoreLibrary/CoreLibrary.nfproj | 8 +- .../System/Array.Enumerators.cs | 101 ++++++ .../System/Collections/Generic/Comparer.cs | 312 ++++++++++-------- .../Collections/Generic/ComparerHelpers.cs | 93 ------ .../System/Collections/Generic/IComparer.cs | 40 +-- .../System/Collections/Generic/IEnumerable.cs | 19 ++ .../System/Collections/Generic/IEnumerator.cs | 30 ++ .../System/Collections/IEnumerable.cs | 4 +- .../System/Collections/IList.cs | 24 +- .../System/IComparable.cs | 44 ++- 10 files changed, 414 insertions(+), 261 deletions(-) create mode 100644 nanoFramework.CoreLibrary/System/Array.Enumerators.cs delete mode 100644 nanoFramework.CoreLibrary/System/Collections/Generic/ComparerHelpers.cs create mode 100644 nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerable.cs create mode 100644 nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerator.cs diff --git a/nanoFramework.CoreLibrary/CoreLibrary.nfproj b/nanoFramework.CoreLibrary/CoreLibrary.nfproj index cf5e4739..e1501725 100644 --- a/nanoFramework.CoreLibrary/CoreLibrary.nfproj +++ b/nanoFramework.CoreLibrary/CoreLibrary.nfproj @@ -38,7 +38,7 @@ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb true true - default + 13.0 true @@ -66,10 +66,12 @@ + - + + @@ -260,4 +262,4 @@ - \ No newline at end of file + diff --git a/nanoFramework.CoreLibrary/System/Array.Enumerators.cs b/nanoFramework.CoreLibrary/System/Array.Enumerators.cs new file mode 100644 index 00000000..532e4483 --- /dev/null +++ b/nanoFramework.CoreLibrary/System/Array.Enumerators.cs @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; + +#nullable enable + +namespace System +{ + internal abstract class SZGenericArrayEnumeratorBase : IDisposable + { + protected int _index; + protected readonly int _endIndex; + + protected SZGenericArrayEnumeratorBase(int endIndex) + { + _index = -1; + _endIndex = endIndex; + } + + public bool MoveNext() + { + int index = _index + 1; + + if ((uint)index < (uint)_endIndex) + { + _index = index; + + return true; + } + + _index = _endIndex; + + return false; + } + + public void Reset() => _index = -1; + + public void Dispose() + { + } + } + + internal sealed class SZGenericArrayEnumerator : SZGenericArrayEnumeratorBase, IEnumerator + { + private readonly T[]? _array; + + /// Provides an empty enumerator singleton. + /// + /// If the consumer is using SZGenericArrayEnumerator elsewhere or is otherwise likely + /// to be using T[] elsewhere, this singleton should be used. Otherwise, GenericEmptyEnumerator's + /// singleton should be used instead, as it doesn't reference T[] in order to reduce footprint. + /// + internal static readonly SZGenericArrayEnumerator Empty = new SZGenericArrayEnumerator(null, 0); + + internal SZGenericArrayEnumerator(T[]? array, int endIndex) + : base(endIndex) + { + Debug.Assert(array == null || endIndex == array.Length); + _array = array; + } + + public T Current + { + get + { + if ((uint)_index >= (uint)_endIndex) + { + throw new InvalidOperationException(); + } + + return _array![_index]; + } + } + + object? IEnumerator.Current => Current; + } + + internal abstract class GenericEmptyEnumeratorBase : IDisposable, IEnumerator + { +#pragma warning disable CA1822 // https://github.com/dotnet/roslyn-analyzers/issues/5911 + public bool MoveNext() => false; + + public object Current + { + get + { + return default; + } + } + + public void Reset() { } + + public void Dispose() { } +#pragma warning restore CA1822 + } +} diff --git a/nanoFramework.CoreLibrary/System/Collections/Generic/Comparer.cs b/nanoFramework.CoreLibrary/System/Collections/Generic/Comparer.cs index ff051537..309edfb2 100644 --- a/nanoFramework.CoreLibrary/System/Collections/Generic/Comparer.cs +++ b/nanoFramework.CoreLibrary/System/Collections/Generic/Comparer.cs @@ -1,129 +1,183 @@ -//// Licensed to the .NET Foundation under one or more agreements. -//// The .NET Foundation licenses this file to you under the MIT license. - -//using System.Diagnostics.CodeAnalysis; -//using System.Runtime.CompilerServices; - -//namespace System.Collections.Generic -//{ -// [Serializable] -// public abstract partial class Comparer : IComparer, IComparer -// { -// // public static Comparer Default is runtime-specific - -// //public static Comparer Create(Comparison comparison) -// //{ -// // ArgumentNullException.ThrowIfNull(comparison); - -// // return new ComparisonComparer(comparison); -// //} - -// public abstract int Compare(T? x, T? y); - -// int IComparer.Compare(object? x, object? y) -// { -// if (x == null) return y == null ? 0 : -1; -// if (y == null) return 1; -// if (x is T && y is T) return Compare((T)x, (T)y); - -// throw new ArgumentException(); -// } -// } - -// internal sealed class ComparisonComparer : Comparer -// { -// //private readonly Comparison _comparison; - -// //public ComparisonComparer(Comparison comparison) -// //{ -// // _comparison = comparison; -// //} - -// public override int Compare(T? x, T? y) => _comparison(x!, y!); -// } - -// // Note: although there is a lot of shared code in the following -// // comparers, we do not incorporate it into a base class for perf -// // reasons. Adding another base class (even one with no fields) -// // means another generic instantiation, which can be costly esp. -// // for value types. -// [Serializable] -// // Needs to be public to support binary serialization compatibility -// public sealed partial class GenericComparer : Comparer where T : IComparable? -// { -// public override int Compare(T? x, T? y) -// { -// if (x != null) -// { -// if (y != null) return x.CompareTo(y); -// return 1; -// } -// if (y != null) return -1; -// return 0; -// } - -// // Equals method for the comparer itself. -// public override bool Equals([NotNullWhen(true)] object? obj) => -// obj != null && GetType() == obj.GetType(); - -// public override int GetHashCode() => -// GetType().GetHashCode(); -// } - -// [Serializable] -// // Needs to be public to support binary serialization compatibility -// public sealed class NullableComparer : Comparer -// { -// public NullableComparer() { } - -// public override int Compare(T? x, T? y) -// { -// if (x.HasValue) -// { -// if (y.HasValue) return Comparer.Default.Compare(x.value, y.value); -// return 1; -// } -// if (y.HasValue) return -1; -// return 0; -// } - -// // Equals method for the comparer itself. -// public override bool Equals([NotNullWhen(true)] object? obj) => -// obj != null && GetType() == obj.GetType(); - -// public override int GetHashCode() => -// GetType().GetHashCode(); -// } - -// [Serializable] -// // Needs to be public to support binary serialization compatibility -// public sealed partial class ObjectComparer : Comparer -// { -// public override int Compare(T? x, T? y) -// { -// return Comparer.Default.Compare(x, y); -// } - -// // Equals method for the comparer itself. -// public override bool Equals([NotNullWhen(true)] object? obj) => -// obj != null && GetType() == obj.GetType(); - -// public override int GetHashCode() => -// GetType().GetHashCode(); -// } - -// [Serializable] -// internal sealed partial class EnumComparer : Comparer -// { -// public EnumComparer() { } - -// // public override int Compare(T x, T y) is runtime-specific - -// // Equals method for the comparer itself. -// public override bool Equals([NotNullWhen(true)] object? obj) => -// obj != null && GetType() == obj.GetType(); - -// public override int GetHashCode() => -// GetType().GetHashCode(); -// } -//} +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +#nullable enable + +namespace System.Collections.Generic +{ + ///// + ///// Provides a base class for implementations of the IComparer{T} generic interface. + ///// + ///// The type of objects to compare. + //[Serializable] + //public abstract partial class Comparer : IComparer, IComparer + //{ + // protected Comparer() + // { + + // } + // //public static Comparer Create(Comparison comparison) + // //{ + // // ArgumentNullException.ThrowIfNull(comparison); + + // // return new ComparisonComparer(comparison); + // //} + + // /// + // /// Returns a default sort-order comparer for the type specified by the generic argument. + // /// + // /// + // /// An object that inherits {T} and serves as a sort-order comparer for type {T}. + // /// + // public static extern Comparer Default + // { + // [MethodImpl(MethodImplOptions.InternalCall)] + // get; + // } + + // public abstract int Compare(T? x, T? y); + + // int IComparer.Compare(object? x, object? y) + // { + // if (x == null) + // { + // return y == null ? 0 : -1; + // } + + // if (y == null) + // { + // return 1; + // } + + // if (x is T && y is T) + // { + // return Compare((T)x, (T)y); + // } + + // throw new ArgumentException(); + // } + //} + + //internal sealed class ComparisonComparer : Comparer + //{ + // private readonly Comparison _comparison; + + // public ComparisonComparer(Comparison comparison) + // { + // _comparison = comparison; + // } + + // public override int Compare(T? x, T? y) => _comparison(x!, y!); + //} + + // Note: although there is a lot of shared code in the following + // comparers, we do not incorporate it into a base class for perf + // reasons. Adding another base class (even one with no fields) + // means another generic instantiation, which can be costly esp. + // for value types. + //[Serializable] + // Needs to be public to support binary serialization compatibility + //public sealed partial class GenericComparer : Comparer where T : IComparable? + //{ + // public override int Compare(T? x, T? y) + // { + // if (x != null) + // { + // if (y != null) + // { + // return x.CompareTo(y); + // } + + // return 1; + // } + // if (y != null) + // { + // return -1; + // } + + // return 0; + // } + + // // Equals method for the comparer itself. + // public override bool Equals([NotNullWhen(true)] object? obj) => + // obj != null && GetType() == obj.GetType(); + + // public override int GetHashCode() => + // GetType().GetHashCode(); + //} + + ///// + ///// + ///// + ///// + //[Serializable] + //public sealed class NullableComparer : Comparer where T : struct + //{ + // public NullableComparer() { } + + // public override int Compare(T? x, T? y) + // { + // if (x.HasValue) + // { + // if (y.HasValue) + // { + // return Comparer.Default.Compare(x.value, y.value); + // } + + // return 1; + // } + + // if (y.HasValue) + // { + // return -1; + // } + + // return 0; + // } + + // // Equals method for the comparer itself. + // public override bool Equals([NotNullWhen(true)] object? obj) => + // obj != null && GetType() == obj.GetType(); + + // public override int GetHashCode() => + // GetType().GetHashCode(); + //} + + //[Serializable] + //public sealed partial class ObjectComparer : Comparer + //{ + // public override int Compare(T? x, T? y) + // { + // return Default.Compare(x, y); + // } + + // // Equals method for the comparer itself. + // public override bool Equals([NotNullWhen(true)] object? obj) => + // obj != null && GetType() == obj.GetType(); + + // public override int GetHashCode() => + // GetType().GetHashCode(); + //} + + //[Serializable] + //internal sealed partial class EnumComparer : Comparer where T : struct, Enum + //{ + // public EnumComparer() { } + + // public override int Compare(T x, T y) + // { + // // TODO: native? + // throw new NotImplementedException(); + // } + + // // Equals method for the comparer itself. + // public override bool Equals([NotNullWhen(true)] object? obj) => + // obj != null && GetType() == obj.GetType(); + + // public override int GetHashCode() => + // GetType().GetHashCode(); + //} +} diff --git a/nanoFramework.CoreLibrary/System/Collections/Generic/ComparerHelpers.cs b/nanoFramework.CoreLibrary/System/Collections/Generic/ComparerHelpers.cs deleted file mode 100644 index a4fcece9..00000000 --- a/nanoFramework.CoreLibrary/System/Collections/Generic/ComparerHelpers.cs +++ /dev/null @@ -1,93 +0,0 @@ -//// Licensed to the .NET Foundation under one or more agreements. -//// The .NET Foundation licenses this file to you under the MIT license. - -//using System.Diagnostics; -//using static System.RuntimeTypeHandle; - -//namespace System.Collections.Generic -//{ -// /// -// /// Helper class for creating the default and . -// /// -// /// -// /// This class is intentionally type-unsafe and non-generic to minimize the generic instantiation overhead of creating -// /// the default comparer/equality comparer for a new type parameter. Efficiency of the methods in here does not matter too -// /// much since they will only be run once per type parameter, but generic code involved in creating the comparers needs to be -// /// kept to a minimum. -// /// -// internal static class ComparerHelpers -// { -// /// -// /// Creates the default . -// /// -// /// The type to create the default comparer for. -// /// -// /// The logic in this method is replicated in vm/compile.cpp to ensure that NGen saves the right instantiations, -// /// and in vm/jitinterface.cpp so the jit can model the behavior of this method. -// /// -// internal static object CreateDefaultComparer(Type type) -// { -// Debug.Assert(type != null && type is RuntimeType); - -// object? result = null; -// var runtimeType = (RuntimeType)type; - -// // If T implements IComparable return a GenericComparer -// if (typeof(IComparable<>).MakeGenericType(type).IsAssignableFrom(type)) -// { -// result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer), runtimeType); -// } -// else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) -// { -// // Nullable does not implement IComparable directly because that would add an extra interface call per comparison. -// var embeddedType = (RuntimeType)type.GetGenericArguments()[0]; -// result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer), embeddedType); -// } -// // The comparer for enums is specialized to avoid boxing. -// else if (type.IsEnum) -// { -// result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumComparer<>), runtimeType); -// } - -// return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectComparer), runtimeType); -// } - -// ///// -// ///// Creates the default . -// ///// -// ///// The type to create the default equality comparer for. -// ///// -// ///// The logic in this method is replicated in vm/compile.cpp to ensure that NGen saves the right instantiations. -// ///// -// //internal static object CreateDefaultEqualityComparer(Type type) -// //{ -// // Debug.Assert(type != null && type is RuntimeType); - -// // object? result = null; -// // var runtimeType = (RuntimeType)type; - -// // if (type == typeof(string)) -// // { -// // return new StringEqualityComparer(); -// // } -// // else if (type.IsAssignableTo(typeof(IEquatable<>).MakeGenericType(type))) -// // { -// // // If T implements IEquatable return a GenericEqualityComparer -// // result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer), runtimeType); -// // } -// // else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) -// // { -// // // Nullable does not implement IEquatable directly because that would add an extra interface call per comparison. -// // var embeddedType = (RuntimeType)type.GetGenericArguments()[0]; -// // result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer), embeddedType); -// // } -// // else if (type.IsEnum) -// // { -// // // The equality comparer for enums is specialized to avoid boxing. -// // result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<>), runtimeType); -// // } - -// // return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectEqualityComparer), runtimeType); -// //} -// } -//} diff --git a/nanoFramework.CoreLibrary/System/Collections/Generic/IComparer.cs b/nanoFramework.CoreLibrary/System/Collections/Generic/IComparer.cs index ab1921c3..dd78f6e0 100644 --- a/nanoFramework.CoreLibrary/System/Collections/Generic/IComparer.cs +++ b/nanoFramework.CoreLibrary/System/Collections/Generic/IComparer.cs @@ -1,22 +1,22 @@ -//// Licensed to the .NET Foundation under one or more agreements. -//// The .NET Foundation licenses this file to you under the MIT license. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -//using System.Runtime.CompilerServices; +#nullable enable -//namespace System.Collections.Generic -//{ -// public abstract partial class Comparer : IComparer, IComparer -// { -// // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small -// // as possible and define most of the creation logic in a non-generic class. -// public static Comparer Default { get; } = (Comparer)ComparerHelpers.CreateDefaultComparer(typeof(T)); -// } - -// internal sealed partial class EnumComparer : Comparer where T : struct, Enum -// { -// public override int Compare(T x, T y) -// { -// return RuntimeHelpers.EnumCompareTo(x, y); -// } -// } -//} +namespace System.Collections.Generic +{ + /// + /// Defines a method that a type implements to compare two objects. + /// + /// The type of objects to compare. This type parameter is contravariant. That is, you can use either the type you specified or any type that is less derived. + public interface IComparer where T : allows ref struct + { + /// + /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other. + /// + /// The first object to compare. + /// The second object to compare. + /// + int Compare(T? x, T? y); + } +} diff --git a/nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerable.cs b/nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerable.cs new file mode 100644 index 00000000..a09be45d --- /dev/null +++ b/nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerable.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Collections.Generic +{ + /// + /// Exposes the enumerator, which supports a simple iteration over a collection of a specified type. + /// + /// The type of objects to enumerate. This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived. + public interface IEnumerable : IEnumerable + where T : allows ref struct + { + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An enumerator that can be used to iterate through the collection. + new IEnumerator GetEnumerator(); + } +} diff --git a/nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerator.cs b/nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerator.cs new file mode 100644 index 00000000..bdb8cf16 --- /dev/null +++ b/nanoFramework.CoreLibrary/System/Collections/Generic/IEnumerator.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Collections.Generic +{ + /// + /// Supports a simple iteration over a generic collection. + /// + /// + /// The type of objects to enumerate. This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived. + /// + + public interface IEnumerator : IDisposable, IEnumerator + where T : allows ref struct + { + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + /// The element in the collection at the current position of the enumerator. + new T Current + { + get; + } + + // NOTE: An implementation of an enumerator using a ref struct T will + // not be able to implement IEnumerator.Current to return that T (as + // doing so would require boxing). It should throw a NotSupportedException + // from that property implementation. + } +} diff --git a/nanoFramework.CoreLibrary/System/Collections/IEnumerable.cs b/nanoFramework.CoreLibrary/System/Collections/IEnumerable.cs index d66ecf55..f4aa575a 100644 --- a/nanoFramework.CoreLibrary/System/Collections/IEnumerable.cs +++ b/nanoFramework.CoreLibrary/System/Collections/IEnumerable.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Collections @@ -11,7 +11,7 @@ public interface IEnumerable /// /// Returns an enumerator that iterates through a collection. /// - /// An IEnumerator object that can be used to iterate through the collection. + /// An object that can be used to iterate through the collection. IEnumerator GetEnumerator(); } } diff --git a/nanoFramework.CoreLibrary/System/Collections/IList.cs b/nanoFramework.CoreLibrary/System/Collections/IList.cs index 90e0f63b..ec6f72c7 100644 --- a/nanoFramework.CoreLibrary/System/Collections/IList.cs +++ b/nanoFramework.CoreLibrary/System/Collections/IList.cs @@ -1,10 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Collections { - using System; - /// /// Represents a non-generic collection of objects that can be individually accessed by index. /// @@ -27,16 +25,16 @@ object this[int index] /// /// Adds an item to the IList. /// - /// The object to add to the IList. + /// The object to add to the IList. /// The position into which the new element was inserted, or -1 to indicate that the item was not inserted into the collection. - int Add(Object value); + int Add(object item); /// /// Determines whether the IList contains a specific value. /// - /// The object to locate in the IList. + /// The object to locate in the IList. /// true if the Object is found in the IList; otherwise, false. - bool Contains(Object value); + bool Contains(object item); /// /// Removes all items from the IList. @@ -68,22 +66,22 @@ bool IsFixedSize /// /// Determines the index of a specific item in the IList. /// - /// The object to locate in the IList. + /// The object to locate in the IList. /// The index of value if found in the list; otherwise, -1. - int IndexOf(Object value); + int IndexOf(object item); /// /// Inserts an item to the IList at the specified index. /// /// The zero-based index at which value should be inserted. - /// The object to insert into the IList. - void Insert(int index, Object value); + /// The object to insert into the IList. + void Insert(int index, object item); /// /// Removes the first occurrence of a specific object from the IList. /// - /// The object to remove from the IList. - void Remove(Object value); + /// The object to remove from the IList. + void Remove(object item); /// /// Removes the IList item at the specified index. diff --git a/nanoFramework.CoreLibrary/System/IComparable.cs b/nanoFramework.CoreLibrary/System/IComparable.cs index f73543dd..27abf9b9 100644 --- a/nanoFramework.CoreLibrary/System/IComparable.cs +++ b/nanoFramework.CoreLibrary/System/IComparable.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System @@ -20,4 +20,46 @@ public interface IComparable int CompareTo(Object obj); } +#if NANOCLR_REFLECTION + +#nullable enable + + /// + /// Defines a generalized comparison method that a value type or class implements to create a type-specific comparison method for ordering or sorting its instances. + /// + /// + /// The type of object to compare. This type parameter is contravariant. That is, you can use either the type you specified or any type that is less derived. + /// + public interface IComparable where T : allows ref struct + { + // Interface does not need to be marked with the serializable attribute + + /// Compares the current instance 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 object. + /// An object to compare with this instance. + /// + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: + /// + /// + /// Value + /// Meaning + /// + /// + /// Less than zero + /// This instance precedes in the sort order. + /// + /// + /// Zero + /// This instance occurs in the same position in the sort order as . + /// + /// + /// Greater than zero + /// This instance follows in the sort order. + /// + /// + /// + int CompareTo(T? other); + } + +#endif + }