Cómo analizar una cadena en una int nullable


Quiero analizar una cadena en un int nullable en C#. IE. 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á, así que 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?

EDIT: Gracias por las sugerencias de TryParse, yo sabía sobre eso, pero funcionó sobre lo mismo. Soy más interesado en saber si hay un método de marco integrado que analizará directamente en un int nullable?

Author: abatishchev, 2008-09-05

20 answers

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

Edit @Glenn int.TryParse está "integrado en el framework". It y int.Parseson la forma de analizar cadenas a ints.

 307
Author: Matt Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-01 23:02:48

Puede hacer esto en una línea, usando el operador condicional y el hecho de que puede convertir null a un tipo nullable (dos líneas, si no tiene un int preexistente, puede reutilizar 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 simple.

int? val = Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null;
 137
Author: McKenzieG1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-06 14:06:24

Lo siento, no pude resistir-tenía este problema y Google me trajo aquí, pero terminé con esto (después de todo, un if y 2 returns es soo largo aliento!):

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

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

 29
Author: Duckboy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-28 01:26:25

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

Existe este enfoque que analizará directamente a 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 valores no válidos, por lo que necesitará capturar 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 puede ser se utiliza para análisis no nullables, así como nullable:

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

NB: Hay un método isValid en el convertidor que puede usar en lugar de capturar la excepción (las excepciones lanzadas resultan en sobrecarga innecesaria si se espera). Desafortunadamente, solo funciona desde. NET 4, pero todavía hay un problema por el que no comprueba su configuración regional al validar los formatos de fecha y hora correctos, consulte error 93559.

 15
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-28 23:56:28

Prueba esto:

public static int? ParseNullableInt(this string value)
{
    int intValue;
    if (int.TryParse(value, out intValue))
        return intValue;
    return null;
}
 8
Author: Joseph Daigle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-07 11:01:11

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 el requriement donde analizar null, la versión de TryParse no lanzaría un error en, por ejemplo, ToNullableInt32(XXX). Eso puede introducir errores silenciosos no deseados.

 6
Author: mortb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-30 00:24:43

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

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

 4
Author: Lyskespark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-21 11:43:14

Usted puede olvidar todas las demás respuestas-hay una gran 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();
 4
Author: Pavel Hodek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-10 09:04:37

Lo siguiente debería funcionar para cualquier tipo de estructura. Está basado fuera de código por Matt Manela de MSDN forums . Como señala Murph, el manejo de excepciones podría ser costoso en comparación con el uso del método Types dedicated TryParse.

        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);
 3
Author: Daniel Ballinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 21:30:10

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);
}
 2
Author: Qi Luo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-19 07:40:50

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

No lo hay.

 1
Author: Orion Edwards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-28 01:31:05

Sentí que debía compartir la mía, que es un poco más genérica.

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 se ve más limpia. Si no se llama muchas veces con cadenas inválidas, no es tan importante. Si el rendimiento es un problema, tenga en cuenta que al usar los métodos TryParse, debe especificar el parámetro type de ParseBy, ya que el compilador no puede inferirlo. También tuve que definir un delegado como fuera la palabra clave 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.

 1
Author: orcun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-24 13:54:05

Encontré y adapté algún código para una clase genérica 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
{
    /// <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;
        }
    }
}
 1
Author: John Dauphine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-15 19:13:21

Se me ha ocurrido este, que ha satisfecho 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 bloques try{} catch{} y sin que el compilador se quejara de inferir un tipo nullable dentro del método framework)

private static bool TryParseNullableInt(this string s, out int? result)
{
    int i;
    result = int.TryParse(s, out i) ? (int?)i : null;
    return result != null;
}
 1
Author: wmoecke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-20 15:01:42
    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;
    }
 1
Author: Crivelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-08 07:05:10

Sugeriría los siguientes métodos de extensión para el análisis de cadenas en el 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();
        }
 1
Author: Aleksandr Neizvestnyi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-12 09:00:09

Debes nunca usar una excepción si no tienes 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 podrías hacer algo con un método de extensión en 3.5, pero el código sería más o menos el mismo.

 0
Author: Murph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-05 10:58:50

Usando delegados, el siguiente código es capaz de proporcionar reusabilidad si usted encuentra que necesita el análisis nullable para más de un tipo de estructura. He mostrado tanto el .Parse () and .TryParse() versiones 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));
    }
  }
 0
Author: umbyersw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-07 22:49:20

Sugiero código abajo. Puede trabajar con excepción, cuando se produjo el 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 (fill int? Edad propiedad de una persona clase):

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); });
 0
Author: lison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-10 10:47:40

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

(Nullable<int>)int.Parse(stringVal);

?

 -1
Author: Leigh Bowers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-11 15:29:38