2010-07-25 22 views
67

Estoy tratando de escribir un método de extensión en tipos numéricos para ser utilizado en un marco de prueba fluido que estoy construyendo. Básicamente, quiero hacer esto:Restricción genérica para hacer coincidir los tipos numéricos

public static ShouldBeGreaterThan<T>(this T actual, T expected, string message) 
    where T : int || T: double || etc... 

Sólo where T : struct no hace, ya que también coincidirá con string y bool, y posiblemente algo más que me olvido. ¿Hay algo que pueda hacer para hacer coincidir solo los tipos numéricos? (Específicamente, los tipos que implementan los operadores > y <, para que pueda compararlos ... Si esto significa que también estoy haciendo coincidir fechas, en realidad no importa; la extensión seguirá haciendo lo que espero)

+6

Jon Skeet y Mark Gravell reunieron algunas clases interesantes para esto: http://www.yoda.arachsys.com/csharp/genericoperators.html –

+10

@ Dan en realidad es "Marc", pero te dejaré salir - muy pocas personas lo hacen bien; p –

Respuesta

48

En este caso, desea restringir su genérico a la interfaz IComparable, que le da acceso al método CompareTo, ya que esta interfaz le permite responder la pregunta ShouldBeGreaterThan.

Los tipos numéricos implementarán esa interfaz y el hecho de que también funciona en cadenas no debería molestarte demasiado.

+1

Esta es una solución mejor que una interfaz de operador más general para tipos numéricos, al menos para este problema. –

+0

¿Existe alguna manera de permitir el uso de '==' y '>' etc. en lugar de '.Equals()' y '.CompareTo'? –

5

Stackoverflow está plagado de este tipo de preguntas. Take a look at this search. C# no admite una forma de definir un tipo genérico restringido por números. Desafortunadamente, su mejor opción es implementar el método de extensión en todos los objetos y hacer un cambio según el tipo o crear un conjunto de métodos para entradas, dobles, flotantes, etc.

15
public static bool IsGreaterThan<T>(this T actual, T comp) where T : IComparable<T> 
{ 
    return actual.CompareTo(comp) > 0; 
} 

Puede agregar la restricción de estructura si así lo desea.

6

Es difícil limitarlo solo a los números, ya que no hay nada en común como INumeric para usar como filtro. En realidad, sospecho que el enfoque más fácil aquí es , no, insista en la restricción y use Comparer<T>.Default.Compare dentro del método.

Este tipo incorporado soporta tanto el genérico IComparable<T> y la no genérico IComparable, y apoya ref-tipos, de valor de tipo y uso levantado a través de Nullable<T>.

Por completo el uso del operador, un vistazo a MiscUtil's Operator class y GreaterThan etc, que puede ser útil si realmente desea utilizar el operador (en lugar de la interfaz). También proporciona acceso a los otros operadores como Add etc.

+0

Marc Gravell dijo "es ** difícil ** limitar a solo números" pero es ** posible ** tanto en tiempo de ejecución como en tiempo de compilación. Consulte mi respuesta a "¿Existe alguna restricción que restrinja mi método genérico a los tipos numéricos?" question.https: //stackoverflow.com/questions/32664/is-there-a-constraint-that-restricts-my-generic-method-to-numeric-types –

+1

@Erez que funcionará, pero es la muerte de código crítico de rendimiento: gran cantidad de boxeo y verificación de tipos. En algún lugar del período C# 7.2-C# 8.0 es probable que veamos adiciones a los genéricos para hacer esto de manera mucho más eficiente. –

+0

No puedo esperar hasta que esto sea compatible con Microsoft. –

38
where T : struct, 
      IComparable, 
      IComparable<T>, 
      IConvertible, 
      IEquatable<T>, 
      IFormattable 

Eso es lo más cerca que puedo llegar a una limitación numérica. Todos los tipos numéricos implementan estas 5 interfaces, pero IFormattable no está implementado por bool, y las cadenas son un tipo de referencia, por lo que no son aplicables.

Hay algunas otras cosas que implementan estos: DateTime, por ejemplo, por lo que no es realmente necesario, pero evita muchas instancias que no desea.

+0

Incluso con esto, parece que no puedo usar operaciones matemáticas comunes. 'Operator '==' no se puede aplicar a operandos de tipo 'T' y 'float'' –

Cuestiones relacionadas