2008-11-20 31 views
11

Estoy trabajando en una herramienta donde necesito convertir valores de cadena a sus tipos de objetos adecuados. P.ej. convierta una cadena como "2008-11-20T16:33:21Z" en un valor de DateTime. Los valores numéricos como "42" y "42.42" se deben convertir a un valor de Int32 y un valor de Double, respectivamente.Cómo determinar si una cadena es un número en C#

¿Cuál es el mejor y más eficiente enfoque para detectar si una cadena es un número entero o un número? ¿Son Int32.TryParse o Double.TryParse el camino a seguir?

Respuesta

9

En términos de eficiencia, sí, TryParse es generalmente la ruta preferida.

Si se puede saber (por ejemplo, mediante la reflexión) el tipo de destino de antemano - pero no quiero tener que utilizar un gran bloque switch, que podría estar interesado en el uso de TypeConverter - por ejemplo:

 DateTime foo = new DateTime(2008, 11, 20); 
     TypeConverter converter = TypeDescriptor.GetConverter(foo); 
     string s = converter.ConvertToInvariantString(foo); 
     object val = converter.ConvertFromInvariantString(s); 
20

Int.TryParse y Double.TryParse tienen la ventaja de realmente devolver el número.

Algo como Regex.IsMatch("^\d+$") tiene el inconveniente de que todavía tiene que analizar la cadena de nuevo para obtener el valor.

+0

El otro beneficio adicional es que el método TryParse devuelve una variable booleana, por lo que es fácil codificar sus escenarios de éxito y falla al analizar el número. –

+0

pero si solo te importa si es un número entero o no, TryParse tiene la ventaja de que debes declarar una variable para el parámetro out –

2

Recomendaría .TryParse() personalmente. Eso es lo que uso de todos modos. Eso es si sus datos van a estar equivocados de vez en cuando. Si está seguro de que las cadenas entrantes podrán convertirse en enteros o dobles sin un enganche, el .Parse() es más rápido.

Aquí hay una interesante link para apoyar esto.

0

Manteniendo la idea de un convertidor para omitir un bloque de interruptores, puede utilizar el concepto de Duck Typing. Básicamente, desea convertir una cadena en X, por lo que crea un método que llamará X.TryParse (cadena, fuera X x) si X tiene TryParse en él, de lo contrario no se molestará (o supongo que podría lanzar un error). ¿Cómo harías esto? Reflexión y genéricos

Básicamente, tendría un método que tomaría un tipo y usaría la reflexión para ver si tiene TryParse en él. Si encuentra un método así, llámelo y devuelva lo que TryParse logró obtener. Esto funciona bien con casi cualquier tipo de valor, como Decimal o DateTime.

public static class ConvertFromString 
{ 
    public static T? ConvertTo<T>(this String numberToConvert) where T : struct 
    { 
    T? returnValue = null; 

    MethodInfo neededInfo = GetCorrectMethodInfo(typeof(T)); 
    if (neededInfo != null && !numberToConvert.IsNullOrEmpty()) 
    { 
     T output = default(T); 
     object[] paramsArray = new object[2] { numberToConvert, output }; 
     returnValue = new T(); 

     object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray); 

     if (returnedValue is Boolean && (Boolean)returnedValue) 
     { 
     returnValue = (T)paramsArray[1]; 
     } 
     else 
     { 
     returnValue = null; 
     }  
    } 

    return returnValue; 
    } 
} 

Dónde GetCorrectMethodInfo sería algo como esto:

private static MethodInfo GetCorrectMethodInfo(Type typeToCheck) 
{ 

    MethodInfo returnValue = someCache.Get(typeToCheck.FullName); 

    if(returnValue == null) 
    { 
    Type[] paramTypes = new Type[2] { typeof(string), typeToCheck.MakeByRefType() }; 
    returnValue = typeToCheck.GetMethod("TryParse", paramTypes); 
    if (returnValue != null) 
    { 
     CurrentCache.Add(typeToCheck.FullName, returnValue); 
    } 
    } 

    return returnValue; 
} 

Y uso sería:

decimal? converted = someString.ConvertTo<decimal>(); 

Odio enchufar a mí mismo, pero tengo esta totalmente explicado aquí:

GetCorrectMethodInfo

Rest of It

Cuestiones relacionadas