¿Cómo comparo valores de tipos genéricos?
Lo he reducido a una muestra mínima:
public class Foo<T> where T : IComparable
{
private T _minimumValue = default(T);
public bool IsInRange(T value)
{
return (value >= _minimumValue); // <-- Error here
}
}
El error es:
El operador '> =' no se puede aplicar a operandos de tipo 'T' y 'T'.
¿¡Que demonios!? T
Ya se ve limitado a IComparable
, e incluso cuando constreñir a los tipos de valor ( where T: struct
), todavía no podemos aplicar cualquiera de los operadores <
, >
, <=
, >=
, ==
o !=
. (Sé que Equals()
existen soluciones alternativas para ==
y !=
, pero no ayuda para los operadores relacionales).
Entonces, dos preguntas:
- ¿Por qué observamos este comportamiento extraño? ¿Qué nos impide comparar los valores de los tipos genéricos que se sabe que son
IComparable
? ¿No frustra de alguna manera todo el propósito de las restricciones genéricas? - ¿Cómo resuelvo esto, o al menos lo soluciono?
(Me doy cuenta de que ya hay un puñado de preguntas relacionadas con este problema aparentemente simple, pero ninguno de los hilos da una respuesta exhaustiva o viable, así que aquí).
fuente
IComparable
sobrecarga de los operadores de comparación es que hay situaciones en las queX.Equals(Y)
debería devolver falso, peroX.CompareTo(Y)
debería devolver cero (lo que sugiere que ningún elemento es más grande que el otro) [por ejemplo, unExpenseItem
puede tener un orden natural con respecto aTotalCost
, y puede haber ningún pedido natural para artículos de gastos cuyo costo es el mismo, pero eso no significa que todos los artículos de gastos que cuestan $ 3,141.59 deben considerarse equivalentes a todos los demás artículos que cuestan lo mismo.==
lógicamente podrían significar. En algunos contextos, es posibleX==Y
que sea verdadero, whileX.Equals(Y)
es falso, y mientras que en otros contextosX==Y
podría ser falso, whileX.Equals(Y)
es verdadero. Incluso si los operadores pueden ser sobrecargados de interfaces, sobrecarga<
,<=
,>
y>=
en cuanto aIComparable<T>
que podría dar la impresión de que==
y!=
también sería sobrecargado en tales términos. Si C #, como vb, hubiera rechazado el uso de==
tipos de clases para los que no estaba sobrecargado, eso podría no haber sido tan malo, pero ...==
para representar tanto un operador de igualdad sobrecargable como una prueba de igualdad de referencia no sobrecargable.