Open virzak opened 3 years ago
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.
IComparable<T>
Notes-to-Implementers say to use the type implementing the interface as T
(ie. for an IComparable<T>
to itself). I haven't seen examples in .NET of types implementing IComparable<some other type>
. This is likely because if our type T
implements IComparable<TOther>
, it places the onus on TOther
to implement IComparable<T>
for things to make sense, which is not something we can guarantee.
Having said that, System.MemoryExtensions.BinarySearch
methods implement a slightly different flavor, where it is the other type (ie. comparable) that needs to implement IComparable<T>
instead of T
implementing IComparable<TOther>
. This extended BinarySearch might suit your needs if you can wrap your T[]
as Span<T>
.
Example:
abstract public record MyBase(Guid Id, double Distance) : IComparable<double>
{
public int CompareTo(double other) => Distance.CompareTo(other);
}
public record Bridge(Guid Id, double Distance) : MyBase(Id, Distance) { }
readonly struct MyBaseComparableOnDistance : IComparable<MyBase> // struct in hopes of GC-efficiency
{
readonly double _distance;
public MyBaseComparableOnDistance(double distance) => _distance = distance;
public int CompareTo(MyBase other) => other is null ? 1 : _distance.CompareTo(other.Distance);
}
static int FindPrevious<T>(double distance, T[] array) where T : MyBase
{
var comparable = new MyBaseComparableOnDistance(distance);
return MemoryExtensions.BinarySearch<T>(array, comparable); // still boxed by interface cast :(
}
void Main()
{
var bridges = new Bridge[]
{
new(Guid.NewGuid(), 1),
new(Guid.NewGuid(), 3),
new(Guid.NewGuid(), 5),
};
var result = FindPrevious(5, bridges);
Console.WriteLine(result);
}
Background and Motivation
Following classes are present in the library - think of features of the road:
Some other class contains Arrays of the derived classes
The code to find a previous feature of the road looks as follows:
There is currently no way to use any other type with generics. MyBase, must be the type of the value to compare to, thus it can't be made abstract.
Closest existing non generic implementation is: System.Array.BinarySearch(Array, Object, IComparer)
It requires IComparer
Proposed API
Usage Examples
Because the comparison is mostly done by can be implemented.
Also, since the
Distance
, IComparableBinarySearch
takes a double, there is no need to instantiate MyBase and it is markedabstract
Alternative / Complimentary Design
A more involved design would be to introduce:
and use is in System.Array
Ideally both could be implemented.
Risks
No known risks