Pregunta

Quiero analizar una cadena en un int que acepta valores NULL en C#.es decir.Quiero recuperar el valor int de la cadena o nulo si no se puede analizar.

Tenía la esperanza de que esto funcionara.

int? val = stringVal as int?;

Pero eso no funcionará, así que la forma en que lo estoy haciendo ahora es que escribí 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;
        }
    }
}   

¿Existe una mejor manera de hacer esto?

EDITAR: Gracias por las sugerencias de TryParse, lo sabía, pero funcionó más o menos igual.Estoy más interesado en saber si existe un método de marco integrado que analizará directamente en un int que acepta valores NULL.

¿Fue útil?

Solución

int.TryParse Probablemente sea 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".Eso y int.Parse son el forma de analizar cadenas en enteros.

Otros consejos

Puedes hacer esto en una línea, usando el operador condicional y el hecho de que puedes transmitir null a un tipo que acepta valores NULL (dos líneas, si no tiene un int preexistente, puede reutilizarlo para la salida de TryParse):

Pre C#7:

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

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

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

Tuve este problema y terminé con esto (después de todo, un if y 2 return¡Es muy prolijo!):

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

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

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

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

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

Este enfoque todavía se puede utilizar para análisis que no aceptan valores NULL así como para análisis que aceptan NULL:

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

NÓTESE BIEN: Hay un método IsValid en el convertidor que puede usar en lugar de capturar la excepción (las excepciones lanzadas dan como resultado gastos generales innecesarios si se espera).Desafortunadamente, solo funciona desde .NET 4, pero todavía hay un problema por el cual no verifica su configuración regional al validar los formatos DateTime correctos, consulte error 93559.

Prueba esto:

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

Tema antiguo, 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 requisito sobre dónde analizar nulo, la versión TryParse no arrojaría un error, por ejemplo.ParaNullableInt32(XXX).Esto puede introducir errores silenciosos no deseados.

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

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

Por supuesto, esta es una solución genérica que solo requiere que el argumento genérico tenga un método estático "Parse(string)".Esto funciona para números, booleanos, DateTime, etc.

var result = int.TryParse(foo, out var f) ? f : default(int?);

Fuentes:

Puede olvidar todas las demás respuestas; existe una excelente solución genérica:http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

Esto le permite escribir 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.Está basado en el código de Matt Manela de los foros de MSDN.Como señala Murph, el manejo de excepciones podría ser costoso en comparación con el uso del método TryParse dedicado a tipos.

        public static bool TryParseStruct<T>(this string value, out Nullable<T> result)
            where T: struct 
        {
            if (string.IsNullOrEmpty(value))
            {
                result = new Nullable<T>();

                return true;
            }

            result = default(T);
            try
            {
                IConvertible convertibleString = (IConvertible)value;
                result = new Nullable<T>((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<int>(out resultOne);
        Assert.IsTrue(successOne);
        Assert.AreEqual(1, resultOne);

        string parseEmpty = string.Empty;
        int? resultEmpty;
        bool successEmpty = parseEmpty.TryParseStruct<int>(out resultEmpty);
        Assert.IsTrue(successEmpty);
        Assert.IsFalse(resultEmpty.HasValue);

        string parseNull = null;
        int? resultNull;
        bool successNull = parseNull.TryParseStruct<int>(out resultNull);
        Assert.IsTrue(successNull);
        Assert.IsFalse(resultNull.HasValue);

        string parseInvalid = "FooBar";
        int? resultInvalid;
        bool successInvalid = parseInvalid.TryParseStruct<int>(out resultInvalid);
        Assert.IsFalse(successInvalid);

Sugeriría seguir los métodos de extensión para el análisis de cadenas en un valor int 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();
        }

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

public static Nullable<T> ParseNullable<T>(string s, Func<string, T> parser) where T : struct
{
    if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(s.Trim())) return null;
    else return parser(s);
}

static void Main(string[] args)
{
    Nullable<int> i = ParseNullable("-1", int.Parse);
    Nullable<float> dt = ParseNullable("3.14", float.Parse);
}

Estoy más interesado en saber si existe un método de marco integrado que analizará directamente en un int que acepta valores NULL.

No lo hay.

Sentí que deberí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>(int.TryParse);

Solución:

public static class NullableParse
{
    public static Nullable<T> ParseBy<T>(this string input, Func<string, T> parser)
        where T : struct
    {
        try
        {
            return parser(input);
        }
        catch (Exception exc)
        {
            return null;
        }
    }

    public delegate bool TryParseDelegate<T>(string input, out T result);

    public static Nullable<T> ParseBy<T>(this string input, TryParseDelegate<T> 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 parece más limpia.Si no se llama muchas veces con cadenas no válidas, no es tan importante.Si el rendimiento es un problema, tenga en cuenta que cuando utilice métodos TryParse, debe especificar el parámetro de tipo de ParseBy, ya que el compilador no puede inferirlo.También tuve que definir un delegado ya que 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, también puedes usarlo con otras estructuras, es decir.decimal, fecha y hora, guid, etc.

Encontré y adapté algo de código para una clase Generic NullableParser.El código completo está en mi blog. TryParse anulable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace SomeNamespace
{
    /// <summary>
    /// A parser for nullable types. Will return null when parsing fails.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    ///
    public static class NullableParser<T> where T : struct
    {
        public delegate bool TryParseDelegate(string s, out T result);
        /// <summary>
        /// A generic Nullable Parser. Supports parsing of all types that implements the tryParse method;
        /// </summary>
        /// <param name="text">Text to be parsed</param>
        /// <param name="result">Value is true for parse succeeded</param>
        /// <returns>bool</returns>
        public static bool TryParse(string s, out Nullable<T> 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>((T)convertableString.ToType(typeof(T),
                            CultureInfo.CurrentCulture));
                        success = true;
                    }
                    else
                    {
                        success = false;
                        result = null;
                    }
                }
            }
            catch
            {
                success = false;
                result = null;
            }
            return success;
        }
    }
}
    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;
    }

Debería nunca use una excepción si no es necesario: la sobrecarga es horrible.

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

Al utilizar delegados, el siguiente código puede proporcionar reutilización si necesita el análisis anulable para más de un tipo de estructura.He mostrado las versiones .Parse() y .TryParse() aquí.

Este es un ejemplo de uso:

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

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

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

Se me ocurrió este, que satisface mis requisitos (quería que mi método de extensión emulara lo más cerca posible el retorno del TryParse del marco, pero sin los bloques try{} catch{} y sin que el compilador se quejara de inferir un tipo anulable dentro del método 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;
}

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

public static class Utils {      
public static bool TryParse<Tin, Tout>(this Tin obj, Func<Tin, Tout> onConvert, Action<Tout> onFill, Action<Exception> 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<int?> onFill, Action<Exception> onError) {
  return Utils.TryParse(str
    , s => string.IsNullOrEmpty(s) ? null : (int?)int.Parse(s)
    , onFill
    , onError);
}
public static bool TryParse(this string str, Action<int> onFill, Action<Exception> onError) {
  return Utils.TryParse(str
    , s => int.Parse(s)
    , onFill
    , onError);
}
}

Utilice este método de extensión en el código (completar int?Propiedad de edad de una clase de persona):

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>)int.Parse(stringVal);

?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top