2012-10-01 9 views
16

Escenariocadena Parse en tipo numérico anulable (1 o 2 liner)

analizar una cadena en un tipo numérico anulable. Si el análisis no tiene éxito, el resultado debe ser nulo; de lo contrario, el resultado debería ser el valor analizado.

Pregunta

Para lograr esto, siempre he utilizado el siguiente método simple pero largamente molesto:

string numericString = "..."; 

decimal? numericValue; 
decimal temp; 
if (decimal.TryParse(numericString, out temp)) 
{ 
    numericValue = temp; 
} 
else 
{ 
    numericValue = null; 
} 

uso el método anterior porque la siguiente no se compila:

decimal temp; 
decimal? numericValue = decimal.TryParse(numericString, out temp) ? temp : null; 

¿Alguien sabe de una versión de la primera un poco de código que es tan corto, ordenado y legible como el segundo bit? Sé que siempre podría escribir un método de extensión que encapsule el primer bit de código, pero me pregunto si hay alguna manera de hacer lo que quiero sin un método de extensión.

Respuesta

26

Una sencilla encasillado explícita hace que sea compilables:

decimal temp; 
// typecast either 'temp' or 'null' 
decimal? numericValue = 
    decimal.TryParse(numericString, out temp) ? temp : (decimal?)null; 

Otra opción es utilizar el operador default del tipo anulable deseada:

decimal temp; 
// replace null with default 
decimal? numericValue = 
    decimal.TryParse(numericString, out temp) ? temp : default(decimal?); 
+0

o '? (decimal?) temp: null; 'solo para agregar otro aspecto. – Marc

+3

Prefiero usar 'default (decimal?)', Me parece más legible que un molde ... –

+0

@Thomas Me gusta eso. – Dan

11

me gustaría hacer algo como esto:

public delegate bool TryParseDelegate<T>(string str, out T value); 

public static T? TryParseOrNull<T>(TryParseDelegate<T> parse, string str) where T : struct 
{ 
    T value; 
    return parse(str, out value) ? value : (T?)null; 
} 

decimal? numericValue = TryParseOrNull<decimal>(decimal.TryParse, numericString); 

O podría hacer que sea un método de extensión:

public static T? TryParseAs<T>(this string str, TryParseDelegate<T> parse) where T : struct 
{ 
    T value; 
    return parse(str, out value) ? value : (T?)null; 
} 

decimal? numericValue = numericString.TryParseAs<decimal>(decimal.TryParse); 
+2

+1 para un método genérico que podría usarse para 'DateTime',' bool', 'int',' long', 'double', etc. – Dan

5

Sólo factorizar a un método de extensión:

public static decimal? ParseDecimal(this string s) 
{ 
    decimal d; 
    if (decimal.TryParse(s, out d)) 
     return d; 
    return null; 
} 

A continuación, puede utilizar de esta manera:

numericValue = numericString.TryParseDecimal(); 
4

¿Qué tal:

decimal? numericValue = 
    decimal.TryParse(numericString, out temp) ? temp : null as decimal?; 

Esto hace NumericValue null si el lanzamiento falla, y es bonito y limpio.

2

El problema es que la temperatura es decimal y nula ... es nula. Debido a que no son del mismo tipo, la comparación entre los dos falla y se obtiene un error.

Prueba cualquiera:

decimal? numericValue = decimal.TryParse(numericString, out temp) ? (decimal?)temp : null; 

o

decimal? numericValue = decimal.TryParse(numericString, out temp) ? (decimal?)temp : (decimal?)null; 
1

creo que debe envolver en un método para facilitar la lectura:

private decimal? ParseOrDefault(string decimalAsString, decimal? defaultIfInvalidString=null) 
{ 
    decimal result; 
    if (decimal.TryParse(decimalAsString, out result)) 
     return result; 
    return defaultIfInvalidString; 
} 

[Test] 
public void ParseOrDefaultTest() 
{ 
    decimal? actual = ParseOrDefault("12", null); 
    Assert.AreEqual(12m,actual); 

    actual = ParseOrDefault("Invalid string", null); 
    Assert.AreEqual(null, actual); 
}