Cómo analizar una cadena en un int nullable

Estoy queriendo analizar una cadena en una int nullable en C #. es decir. Quiero recuperar el valor int de la cadena o null si no se puede analizar.

Esperaba que esto funcionara

int? val = stringVal as int?; 

Pero eso no funcionará, entonces la forma en que lo estoy haciendo ahora es que he escrito este método de extensión

 public static int? ParseNullableInt(this string value) { if (value == null || value.Trim() == string.Empty) { return null; } else { try { return int.Parse(value); } catch { return null; } } } 

¿Hay una mejor manera de hacer esto?

EDITAR: Gracias por las sugerencias de TryParse, lo sabía, pero funcionó de la misma manera. Estoy más interesado en saber si hay un método de marco incorporado que analizará directamente en un int nullable?

int.TryParse es probablemente un poco más fácil:

 public static int? ToNullableInt(this string s) { int i; if (int.TryParse(s, out i)) return i; return null; } 

Editar @Glenn int.TryParse está “integrado en el marco”. It y int.Parse son la forma de analizar cadenas a ints.

Puede hacer esto en una línea, usando el operador condicional y el hecho de que puede convertir el null en un tipo anulable (dos líneas, si no tiene una int preexistente, puede reutilizarla para la salida de TryParse ):

Pre C # 7:

 int tempVal; int? val = Int32.TryParse(stringVal, out tempVal) ? Int32.Parse(stringVal) : (int?)null; 

Con la syntax actualizada de C # 7 que le permite declarar una variable de salida en la llamada al método, esto se simplifica aún más.

 int? val = Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null; 

Lo siento, no pude resistirme: tuve este problema y Google me trajo aquí, pero terminé con esto (después de todo, un if y 2 return s son tan largos …):

 int? ParseNInt (string val) { int i; return int.TryParse (val, out i) ? (int?) i : null; } 

En una nota más seria, trate de no mezclar int , que es una palabra clave C #, con Int32 , que es un tipo .NET Framework BCL, aunque funciona, simplemente hace que el código parezca desordenado.

Glenn Slaven : ¿estoy más interesado en saber si hay un método de marco incorporado que analizará directamente en un int nullable?

Existe este enfoque que analizará directamente un int nullable (y no solo int) si el valor es válido como null o cadena vacía, pero arroja una excepción para los valores no válidos, por lo que deberá capturar la excepción y devolver el valor predeterminado para esas situaciones:

 public static T Parse(object value) { try { return (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.ToString()); } catch { return default(T); } } 

Este enfoque aún se puede usar para análisis sin nulles y anulables:

 enum Fruit { Orange, Apple } var res1 = Parse("Apple"); var res2 = Parse("Banana"); var res3 = Parse("100") ?? 5; //use this for non-zero default var res4 = Parse("45%"); 

NB: Existe un método IsValid en el convertidor que puede usar en lugar de capturar la excepción (las excepciones lanzadas resultan en una sobrecarga innecesaria si se espera). Desafortunadamente, solo funciona desde .NET 4 pero todavía hay un problema por el cual no se verifica tu configuración cuando se validan los formatos correctos de DateTime, consulta el error 93559 .

Prueba esto:

 public static int? ParseNullableInt(this string value) { int intValue; if (int.TryParse(value, out intValue)) return intValue; return null; } 

Viejo tema, pero ¿qué tal?

 public static int? ParseToNullableInt(this string value) { return String.IsNullOrEmpty(value) ? null : (int.Parse(value) as int?); } 

Me gusta más esto como la pregunta donde analizar el nulo, la versión TryParse no arrojaría un error, por ejemplo, ToNullableInt32 (XXX). Eso puede introducir errores silenciosos no deseados.

Siento que mi solución es una solución muy limpia y agradable:

 public static T? NullableParse(string s) where T : struct { try { return (T)typeof(T).GetMethod("Parse", new[] {typeof(string)}).Invoke(null, new[] { s }); } catch (Exception) { return null; } } 

Esta es, por supuesto, una solución genérica que solo requiere que el argumento genérico tenga un método estático “Parse (cadena)”. Esto funciona para números, booleanos, DateTime, etc.

Puede olvidarse de todas las demás respuestas: hay una gran solución genérica: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

Esto le permite escribir un código muy limpio como este:

 string value = null; int? x = value.ConvertOrDefault(); 

y también:

 object obj = 1; string value = null; int x = 5; if (value.TryConvert(out x)) Console.WriteLine("TryConvert example: " + x); bool boolean = "false".ConvertOrDefault(); bool? nullableBoolean = "".ConvertOrDefault(); int integer = obj.ConvertOrDefault(); int negativeInteger = "-12123".ConvertOrDefault(); int? nullableInteger = value.ConvertOrDefault(); MyEnum enumValue = "SecondValue".ConvertOrDefault(); MyObjectBase myObject = new MyObjectClassA(); MyObjectClassA myObjectClassA = myObject.ConvertOrDefault(); 

Lo siguiente debería funcionar para cualquier tipo de estructura. Se basa en el código de Matt Manela de los foros de MSDN . Como Murph señala que el manejo de excepciones podría ser costoso en comparación con el uso del método dedicado TryParse Types.

  public static bool TryParseStruct(this string value, out Nullable result) where T: struct { if (string.IsNullOrEmpty(value)) { result = new Nullable(); return true; } result = default(T); try { IConvertible convertibleString = (IConvertible)value; result = new Nullable((T)convertibleString.ToType(typeof(T), System.Globalization.CultureInfo.CurrentCulture)); } catch(InvalidCastException) { return false; } catch (FormatException) { return false; } return true; } 

Estos fueron los casos de prueba básicos que utilicé.

  string parseOne = "1"; int? resultOne; bool successOne = parseOne.TryParseStruct(out resultOne); Assert.IsTrue(successOne); Assert.AreEqual(1, resultOne); string parseEmpty = string.Empty; int? resultEmpty; bool successEmpty = parseEmpty.TryParseStruct(out resultEmpty); Assert.IsTrue(successEmpty); Assert.IsFalse(resultEmpty.HasValue); string parseNull = null; int? resultNull; bool successNull = parseNull.TryParseStruct(out resultNull); Assert.IsTrue(successNull); Assert.IsFalse(resultNull.HasValue); string parseInvalid = "FooBar"; int? resultInvalid; bool successInvalid = parseInvalid.TryParseStruct(out resultInvalid); Assert.IsFalse(successInvalid); 

Esta solución es genérica sin gastos indirectos de reflexión.

 public static Nullable ParseNullable(string s, Func parser) where T : struct { if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(s.Trim())) return null; else return parser(s); } static void Main(string[] args) { Nullable i = ParseNullable("-1", int.Parse); Nullable dt = ParseNullable("3.14", float.Parse); } 

Estoy más interesado en saber si hay un método de marco incorporado que analizará directamente en un int nullable?

No hay

Sentí que debía compartir el mío, que es un poco más genérico.

Uso:

 var result = "123".ParseBy(int.Parse); var result2 = "123".ParseBy(int.TryParse); 

Solución:

 public static class NullableParse { public static Nullable ParseBy(this string input, Func parser) where T : struct { try { return parser(input); } catch (Exception exc) { return null; } } public delegate bool TryParseDelegate(string input, out T result); public static Nullable ParseBy(this string input, TryParseDelegate parser) where T : struct { T t; if (parser(input, out t)) return t; return null; } } 

La primera versión es más lenta, ya que requiere un try-catch, pero se ve más limpio. Si no se llamará muchas veces con cadenas inválidas, no es tan importante. Si el rendimiento es un problema, tenga en cuenta que al utilizar los métodos TryParse, debe especificar el parámetro de tipo de ParseBy, ya que el comstackdor no lo puede inferir. También tuve que definir un delegado como la palabra clave out no se puede usar dentro de Func <>, pero al menos esta vez el compilador no requiere una instancia explícita.

Finalmente, puede usarlo con otras estructuras también, es decir, decimal, DateTime, Guid, etc.

Encontré y adapté un código para una clase Genérico NullableParser. El código completo está en mi blog Nullable TryParse

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization; namespace SomeNamespace { ///  /// A parser for nullable types. Will return null when parsing fails. ///  ///  /// public static class NullableParser where T : struct { public delegate bool TryParseDelegate(string s, out T result); ///  /// A generic Nullable Parser. Supports parsing of all types that implements the tryParse method; ///  /// Text to be parsed /// Value is true for parse succeeded /// bool public static bool TryParse(string s, out Nullable result) { bool success = false; try { if (string.IsNullOrEmpty(s)) { result = null; success = true; } else { IConvertible convertableString = s as IConvertible; if (convertableString != null) { result = new Nullable((T)convertableString.ToType(typeof(T), CultureInfo.CurrentCulture)); success = true; } else { success = false; result = null; } } } catch { success = false; result = null; } return success; } } } 

He creado este, que ha cumplido con mis requisitos (quería que mi método de extensión emulara lo más cerca posible el retorno del TryParse del framework, pero sin los bloques try {} catch {} y sin que el comstackdor se quejara de inferir un tipo anulable dentro del método de marco)

 private static bool TryParseNullableInt(this string s, out int? result) { int i; result = int.TryParse(s, out i) ? (int?)i : null; return result != null; } 
  public static void Main(string[] args) { var myString = "abc"; int? myInt = ParseOnlyInt(myString); // null myString = "1234"; myInt = ParseOnlyInt(myString); // 1234 } private static int? ParseOnlyInt(string s) { return int.TryParse(s, out var i) ? i : (int?)null; } 

Sugiero seguir los métodos de extensión para el análisis de cadenas en int value con la capacidad de definir el valor predeterminado en caso de que el análisis no sea posible:

 public static int ParseInt(this string value, int defaultIntValue = 0) { return int.TryParse(value, out var parsedInt) ? parsedInt : defaultIntValue; } public static int? ParseNullableInt(this string value) { if (string.IsNullOrEmpty(value)) return null; return value.ParseInt(); } 

Nunca debe usar una excepción si no tiene que hacerlo, la sobrecarga es horrible.

Las variaciones en TryParse resuelven el problema: si quieres ser creativo (para hacer que tu código se vea más elegante), probablemente puedas hacer algo con un método de extensión en 3.5 pero el código sería más o menos el mismo.

Mediante el uso de delegates, el siguiente código puede proporcionar reutilización si considera que necesita el análisis nullable para más de un tipo de estructura. He mostrado las versiones .Parse () y .TryParse () aquí.

Este es un uso de ejemplo:

 NullableParser.TryParseInt(ViewState["Id"] as string); 

Y aquí está el código que te lleva allí …

 public class NullableParser { public delegate T ParseDelegate(string input) where T : struct; public delegate bool TryParseDelegate(string input, out T outtie) where T : struct; private static T? Parse(string input, ParseDelegate DelegateTheParse) where T : struct { if (string.IsNullOrEmpty(input)) return null; return DelegateTheParse(input); } private static T? TryParse(string input, TryParseDelegate DelegateTheTryParse) where T : struct { T x; if (DelegateTheTryParse(input, out x)) return x; return null; } public static int? ParseInt(string input) { return Parse(input, new ParseDelegate(int.Parse)); } public static int? TryParseInt(string input) { return TryParse(input, new TryParseDelegate(int.TryParse)); } public static bool? TryParseBool(string input) { return TryParse(input, new TryParseDelegate(bool.TryParse)); } public static DateTime? TryParseDateTime(string input) { return TryParse(input, new TryParseDelegate(DateTime.TryParse)); } } 

Sugiero el código a continuación. Puede trabajar con excepción cuando se produce un error de conversión.

 public static class Utils { public static bool TryParse(this Tin obj, Func onConvert, Action onFill, Action onError) { Tout value = default(Tout); bool ret = true; try { value = onConvert(obj); } catch (Exception exc) { onError(exc); ret = false; } if (ret) onFill(value); return ret; } public static bool TryParse(this string str, Action onFill, Action onError) { return Utils.TryParse(str , s => string.IsNullOrEmpty(s) ? null : (int?)int.Parse(s) , onFill , onError); } public static bool TryParse(this string str, Action onFill, Action onError) { return Utils.TryParse(str , s => int.Parse(s) , onFill , onError); } } 

Use este método de extensión en el código (fill int? Age property of a person class):

 string ageStr = AgeTextBox.Text; Utils.TryParse(ageStr, i => person.Age = i, exc => { MessageBox.Show(exc.Message); }); 

O

 AgeTextBox.Text.TryParse(i => person.Age = i, exc => { MessageBox.Show(exc.Message); }); 

Me doy cuenta de que este es un tema antiguo, pero no puedes simplemente:

 (Nullable)int.Parse(stringVal); 

?