How to compare the values ​​of generic types?

How to compare the values ​​of common types?

I reduced it to a minimal sample:

public class Foo<T> where T : IComparable { private T _minimumValue = default(T); public bool IsInRange(T value) { return (value >= _minimumValue); // <-- Error here } } 

Mistake:

The operator '> =' cannot be applied to operands of type "T" and "T".

What in the world !? T already bound to IComparable , and even when it binds it to value types ( where T: struct ), we still cannot use any of the < , > , <= , >= , == or != Operators. (I know that workarounds involving Equals() exist for == and != , But that doesn't help for relational operators).

So, two questions:

  • Why are we observing this strange behavior? What prevents us from comparing the values ​​of common types that are known as IComparable ? Can it not somehow surpass the whole purpose of general restrictions?
  • How can I solve this problem or at least get around it?

(I understand that there are already several questions related to this seemingly simple problem, but none of the threads gives an exhaustive or workable answer, so here.)

+56
generics c # icomparable
Jun 25 2018-11-21T00:
source share
8 answers

IComparable does not overload the >= operator. You have to use

 value.CompareTo(_minimumValue) >= 0 
+68
Jun 25 2018-11-21T00:
source share

Operator Overload Problem

Unfortunately, interfaces cannot contain overloaded operators. Try injecting this into your compiler:

 public interface IInequalityComaparable<T> { bool operator >(T lhs, T rhs); bool operator >=(T lhs, T rhs); bool operator <(T lhs, T rhs); bool operator <=(T lhs, T rhs); } 

I don’t know why they didn’t allow this, but I assume that this complicates the definition of the language and it would be difficult to correctly implement the users.

Either this, or designers do not like the possibility of abuse. For example, imagine you are comparing >= on a class MagicMrMeow . Or even on class Matrix<T> . What does the result mean with respect to two values ​​?; Especially when there can be ambiguity?

Official work

Since the above interface is not legal, we have an IComparable<T> interface to get around the problem. It does not execute statements and provides only one method, int CompareTo(T other);

See http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx

The int result is actually three-bit or three-digit (similar to a Boolean , but with three states). This table explains the meaning of the results:

 Value Meaning Less than zero This object is less than the object specified by the CompareTo method. Zero This object is equal to the method parameter. Greater than zero This object is greater than the method parameter. 

Use workspace

To make the equivalent of value >= _minimumValue , you should write:

 value.CompareTo(_minimumValue) >= 0 
+24
Jun 25 2018-11-11T00:
source share

If value can be empty, the current response may fail. Instead, use something like this:

 Comparer<T>.Default.Compare(value, _minimumValue) >= 0 
+11
Nov 07 '14 at 15:18
source share
 public bool IsInRange(T value) { return (value.CompareTo(_minimumValue) >= 0); } 

When working with generated IComparable, fewer or more operators need to be converted to CompareTo calls. No matter which operator you use, keep the values ​​compared in the same order and compare them to zero. ( x <op> y becomes x.CompareTo(y) <op> 0 , where <op> - > , >= , etc.)

Also, I would recommend that the general restriction you use be where T : IComparable<T> . Opposing by itself means that the object can be compared with anything, it is more likely that comparing the object with others of a similar type is more appropriate.

+5
Jun 25 2018-11-21T00:
source share

Instead of value >= _minimValue use the Comparer class:

 public bool IsInRange(T value ) { var result = Comparer<T>.Default.Compare(value, _minimumValue); if ( result >= 0 ) { return true; } else { return false; } } 
+3
Jun 25 2018-11-21T00:
source share

IComparable only creates a function called CompareTo() . Thus, you cannot apply any of the operators you mentioned

+1
Jun 25 2018-11-21T00:
source share

As others have stated, you must explicitly use the CompareTo method. The reason why you cannot use interfaces with operators is because a class can implement an arbitrary number of interfaces without a clear ranking among them. Suppose someone tried to evaluate the expression "a = foo + 5;" when foo implements six interfaces, all of which define a + operator with an integer second argument; which interface should be used for the operator?

The fact that classes can output multiple interfaces makes interfaces very powerful. Unfortunately, this often makes us speak more clearly about what I really want to do.

+1
Jun 25 2018-11-21T00:
source share

I was able to use Peter Hedburg's answer to create some overloaded extension methods for generics. Note that the CompareTo method does not work here, because the type T unknown and does not display this interface. However, I am interested in any alternatives.

I would like to publish in C #, but the Telerik converter does not work in this code. I am not familiar enough with C # to reliably convert it manually. If someone wants to do honors, I would be glad to see that this has been edited accordingly.

 <Extension> <DebuggerStepThrough> Public Sub RemoveDuplicates(Of T)(Instance As List(Of T)) Instance.RemoveDuplicates(Function(X, Y) Comparer(Of T).Default.Compare(X, Y)) End Sub <Extension> <DebuggerStepThrough> Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparison As Comparison(Of T)) Instance.RemoveDuplicates(New List(Of Comparison(Of T)) From {Comparison}) End Sub <Extension> <DebuggerStepThrough> Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparisons As List(Of Comparison(Of T))) Dim oResults As New List(Of Boolean) For i As Integer = 0 To Instance.Count - 1 For j As Integer = Instance.Count - 1 To i + 1 Step -1 oResults.Clear() For Each oComparison As Comparison(Of T) In Comparisons oResults.Add(oComparison(Instance(i), Instance(j)) = 0) Next oComparison If oResults.Any(Function(R) R) Then Instance.RemoveAt(j) End If Next j Next i End Sub 

- EDIT -

I managed to clear this by holding back T to IComparable(Of T) for all methods, as indicated by OP. Note that this restriction requires type T to implement IComparable(Of <type>) .

 <Extension> <DebuggerStepThrough> Public Sub RemoveDuplicates(Of T As IComparable(Of T))(Instance As List(Of T)) Instance.RemoveDuplicates(Function(X, Y) X.CompareTo(Y)) End Sub 
0
Dec 14 '17 at 6:42 on
source share



All Articles