2012-10-01 13 views
16

ScenarioParse stringa in tipo numerico nullable (1 o 2 liner)

analizzare una stringa in un tipo numerico nullable. Se l'analisi non ha esito positivo, il risultato dovrebbe essere nullo; altrimenti il ​​risultato dovrebbe essere il valore analizzato.

Domanda

Per fare questo, ho sempre usato il seguente metodo semplice ma lungamente fastidioso:

string numericString = "..."; 

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

Io uso il metodo di cui sopra, perché seguente non compila:

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

Qualcuno sa di una versione del primo bit di codice che è il più breve, ordinato e leggibile come il secondo bit? So che potrei sempre scrivere un metodo di estensione che incapsula il primo bit di codice, ma mi chiedo se c'è un modo per fare ciò che voglio senza un metodo di estensione.

risposta

26

Una semplice typecast esplicito rende compilabile:

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

Un'altra opzione è quella di utilizzare l'operatore default del tipo nullable desiderata:

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

o '? (decimale?) temp: null; 'solo per aggiungere un altro sguardo. – Marc

+3

Preferisco usare 'default (decimale?)', Lo trovo più leggibile di un cast ... –

+0

@Thomas mi piace. – Dan

11

farei qualcosa di simile:

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); 

Oppure si potrebbe fare un metodo di estensione:

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 per un metodo generico che potrebbe essere usato per 'DateTime',' bool', 'int',' long', 'double', ecc. – Dan

5

Basta fattorizzare ad un metodo di estensione:

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

è possibile utilizzare in questo modo:

numericValue = numericString.TryParseDecimal(); 
4

ne dite:

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

Questo rende numericValue null se il cast fallisce, e lo è bello e pulito.

2

Il problema è che temp è un decimale e null ... è null. Perché non sono dello stesso tipo, il confronto tra i due fallisce e si ottiene un errore.

Prova uno:

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

o

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

Penso che si dovrebbe avvolgerlo in un metodo per una migliore leggibilità:

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); 
} 
Problemi correlati