2010-03-10 23 views
13

Me gustaría crear una función que compruebe si un valor numérico pasado como argumento tiene un valor mayor que cero. Algo como esto:Cómo puedo comparar cualquier tipo numérico a cero en C#

public bool IsGreaterThanZero(object value) 
{ 
    if(value is int) 
    { 
     return ((int)value > 0); 
    } 
    else if(value is float) 
    { 
     // Similar code for float 
    } 

    return false; 
} 

¿Puedo tratar de convertir el objeto pasado como argumento de la función de un tipo de datos numéricos por lo que a continuación se puede comparar a cero en lugar de comprobar para cada tipo en mi sentencia if? Si el lanzamiento falla, devolvería falso. ¿Hay una forma mejor (leer más corta, más legible) para hacer esto?

Editar: Algunos han preguntado sobre si sé el tipo será un valor numérico, por qué el objeto, etc Espero que esto hace las cosas más claras.

Esta función sería parte de un convertidor de Silverlight que implementa la interfaz IValueConverter que tiene una firma de conversión de

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 

Una primera, que sólo quería el convertidor de trabajar con enteros, pero mi imaginación empezó a funcionar salvaje y piense qué pasa si tengo números de coma flotante y otros tipos numéricos. Quería hacer el convertidor lo más flexible posible. Inicialmente pensé que toda esta información adicional se interpondría en el camino de lo que quería hacer, así que no lo incluí en mi pregunta.

+5

¿Por qué es esto preferible usar sólo la > operador? – Nick

+0

¿qué hay de lanzarlo como una cadena? Compararlo con "0" – Luiscencio

+0

@Nick no se puede comparar un int a un objeto ... – Langdon

Respuesta

15

Mi preferencia sería:.

public bool IsGreaterThanZero(object value) 
{ 
    if(value is IConvertible) 
    { 
     return Convert.ToDouble(value) > 0.0; 
    } 

    return false; 
} 

Este se encargará de todos IConvertible tipos de forma segura (que incluye todo el punto flotante y tipos de enteros en el marco, pero también cualquier tipo personalizado).

+0

¿No arrojaría esto una excepción si la persona que llama pasó un valor de cadena no numérico? –

+0

@Mike: Potencialmente, sin embargo, podría manejarse, si fuera necesario, a través de un try/catch. –

+0

@Mike: el OP especificó que esto sería un valor numérico, sin embargo, si eso es cierto, lo anterior está bien. Si no es así, necesitaría manejo de excepciones ... –

2

Probar:

double tempValue; 
if(double.TryParse(value.ToString(), out tempValue) 
{ 
    return (tempValue > 0) 
} 
else 
{ 
    return false; 
} 
+0

Esto no es particularmente eficiente, ya que va a cadena, luego a doble ... –

+0

sí, pero creo que la otra alternativa es usar Convert.ToDouble o algo así, que (A) podría arrojar una excepción y (B) Realmente no sé cuán eficiente es ese. De todos modos, sería ideal si .NET tuviera un Covert.TryToDouble que devolviera un valor booleano en lugar de arrojar una excepción, pero eso no parece existir –

+0

@Mike: vea mi respuesta: básicamente maneja ese caso, sin las conversiones de cadena ... –

1

¿Por qué no Convert.ToDouble o Convert.ToDecimal y luego hacer la comparación? Parece que eso sería manejar la mayoría de los tipos de que alguien pueda pasar en

14

¿Conoce la persona que llama? Si es así, ¿qué tal:

public static bool GreaterThanZero<T>(T value) where T : struct, IComparable<T> 
{ 
    return value.CompareTo(default(T)) > 0; 
} 

No hay conversiones necesario, y debería funcionar para cualquiera de los tipos numéricos integrados - y cualquier tipo de valor sensibles a llegar a ti mismo. (Por ejemplo, esto estaría bien con Duration estructura de Noda Tiempo.)

Tenga en cuenta que la persona que llama no tiene que saber el tipo directamente - que sólo puede conocerlo como otro tipo de parámetro con las mismas limitaciones. Es cierto que esto puede no ser apropiado para su situación, pero pensé que lo mencionaría de todos modos. Si nada sabe el tipo en tiempo de compilación (¡y no le apetece que teclee dinámicamente para hacer el trabajo por usted en C# 4!), Entonces llamar al Convert.ToDouble es probablemente su mejor opción, solo tenga en cuenta que puede tener problemas para System.Numerics.BigInteger de .NET 4.0.

3

Puede evitar boxeo y unboxing utilizando los genéricos:

Aquí es la definición de una función

class GenericComparation { 
    public static bool IsGreaterThanZero<T>(T value) where T : IComparable<T> { 
     // Console.WriteLine(value.GetType().Name) 
     return value.CompareTo(default(T)) > 0; 
    } 
} 

Uso:

Console.WriteLine(GenericComparation.IsGreaterThanZero(1)); 
Console.WriteLine(GenericComparation.IsGreaterThanZero(-1.1)); 
Console.WriteLine(GenericComparation.IsGreaterThanZero(Decimal.Zero)); 
4

Eh? ¿Qué tipos de numéricos te importan?

public bool IsGreaterThanZero(double value) 
{ 
    return value > 0; 
} 

Estos todo el trabajo ...

IsGreaterThanZero((int)2); 
    IsGreaterThanZero((long)2); 
    IsGreaterThanZero((double)2); 
    IsGreaterThanZero((float)2); 
    IsGreaterThanZero((byte)2); 
    IsGreaterThanZero((ulong)2); 
+1

Para mí esta es la mejor respuesta. Escriba safe (sin excepción de transmisión), eficiente (sin conversiones o try/catch) y cubre todas las bases. – Russell

+1

@Russel: Habrá conversiones implícitas en el sitio de llamadas para todo menos un doble. Compruébalo con .Net Reflector. Tampoco funciona implícitamente para Decimal. –

+0

+1 Hightechrider y +1 Russell: Estoy totalmente de acuerdo con ustedes dos. –

1

De esta manera sencilla y rápida de comparar cualquier tipo numérico Para poner a cero es el siguiente:

public bool IsGreaterThanZero(object value) 
{ 
    if (value != null && value.GetType().IsValueType) 
     return System.Convert.ToDouble(value) > 0; 
    return false; 
} 
+0

IsValueType no garantiza que el valor sea numérico. Podría ser una estructura o simplemente un "objeto", o una cadena arbitraria. –

Cuestiones relacionadas