Domanda

Voglio analizzare una stringa in un int nullable in C#.cioè.Voglio recuperare il valore int della stringa o null se non può essere analizzato.

Speravo che funzionasse

int? val = stringVal as int?;

Ma non funzionerà, quindi il modo in cui lo sto facendo ora è che ho scritto questo metodo di estensione

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

Esiste un modo migliore per farlo?

MODIFICARE: Grazie per i suggerimenti TryParse, lo sapevo, ma ha funzionato più o meno lo stesso.Sono più interessato a sapere se esiste un metodo framework integrato che analizzerà direttamente in un int nullable?

È stato utile?

Soluzione

int.TryParse probabilmente è un po' più semplice:

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

Modificare @Glenn int.TryParse è "integrato nel framework".Esso e int.Parse Sono IL modo per analizzare le stringhe in int.

Altri suggerimenti

Puoi farlo in una riga, utilizzando l'operatore condizionale e il fatto che puoi eseguire il cast null a un tipo nullable (due righe, se non hai un int preesistente puoi riutilizzarlo per l'output di TryParse):

Pre Do#7:

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

Con la sintassi aggiornata di C#7 che consente di dichiarare una variabile di output nella chiamata al metodo, tutto diventa ancora più semplice.

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

Ho avuto questo problema e mi sono ritrovato con questo (dopo tutto, an if e 2 returnè così prolisso!):

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

Su una nota più seria, cerca di non mescolare int, che è una parola chiave C#, con Int32, che è un tipo BCL di .NET Framework: sebbene funzioni, rende semplicemente il codice confuso.

Glenn Slaven:Sono più interessato a sapere se esiste un metodo framework integrato che analizzerà direttamente in un INT nullo?

Esiste questo approccio che analizzerà direttamente un int nullable (e non solo un int) se il valore è valido come null o una stringa vuota, ma lancia un'eccezione per valori non validi, quindi dovrai catturare l'eccezione e restituire il valore predefinito per quelle situazioni:

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

Questo approccio può ancora essere utilizzato per analisi non nullable e 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: Esiste un metodo IsValid sul convertitore che puoi utilizzare invece di acquisire l'eccezione (le eccezioni generate danno come risultato spese generali inutili se previsto).Sfortunatamente funziona solo a partire da .NET 4 ma c'è ancora un problema per cui non controlla le impostazioni locali durante la convalida dei formati DateTime corretti, vedere errore 93559.

Prova questo:

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

Vecchio argomento, ma che ne dici di:

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

Mi piace di più perché il requisito in cui analizzare null, la versione TryParse non genererebbe un errore ad es.ToNullableInt32(XXX).Ciò potrebbe introdurre errori silenziosi indesiderati.

Sento che la mia soluzione è una soluzione molto pulita e piacevole:

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

Questa è ovviamente una soluzione generica che richiede solo che l'argomento generics abbia un metodo statico "Parse(string)".Funziona con numeri, booleani, DateTime, ecc.

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

Fonti:

Puoi dimenticare tutte le altre risposte: esiste un'ottima soluzione generica:http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

Ciò ti consente di scrivere codice molto pulito come questo:

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

e anche:

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

Quanto segue dovrebbe funzionare per qualsiasi tipo di struttura.Si basa sul codice di Matt Manela dai forum MSDN.Come sottolinea Murph, la gestione delle eccezioni potrebbe essere costosa rispetto all'utilizzo del metodo TryParse dedicato ai tipi.

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

Questi erano i casi di test di base che ho usato.

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

Suggerirei di seguire i metodi di estensione per l'analisi delle stringhe nel valore int con la possibilità di definire il valore predefinito nel caso in cui l'analisi non sia possibile:

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

Questa soluzione è generica senza sovraccarico di riflessione.

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

Sono più interessato a sapere se esiste un metodo framework integrato che analizzerà direttamente in un int nullable?

Non c'è.

Ho sentito che avrei dovuto condividere il mio che è un po' più generico.

Utilizzo:

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

var result2 = "123".ParseBy<int>(int.TryParse);

Soluzione:

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 prima versione è più lenta poiché richiede un tentativo di cattura ma sembra più pulita.Se non verrà chiamato molte volte con stringhe non valide, non è così importante.Se le prestazioni sono un problema, tieni presente che quando usi i metodi TryParse, devi specificare il parametro del tipo di ParseBy poiché non può essere dedotto dal compilatore.Ho anche dovuto definire un delegato poiché la parola chiave out non può essere utilizzata all'interno di Func<>, ma almeno questa volta il compilatore non richiede un'istanza esplicita.

Infine, puoi usarlo anche con altre strutture, ad es.decimale, DateTime, Guid, ecc.

Ho trovato e adattato del codice per una classe NullableParser generica.Il codice completo è sul mio blog TryParse nullable

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

Dovresti Mai usa un'eccezione se non è necessario: il sovraccarico è orribile.

Le variazioni su TryParse risolvono il problema: se vuoi essere creativo (per rendere il tuo codice più elegante) potresti probabilmente fare qualcosa con un metodo di estensione in 3.5 ma il codice sarebbe più o meno lo stesso.

Utilizzando i delegati, il codice seguente è in grado di fornire la riusabilità se è necessaria l'analisi nullable per più di un tipo di struttura.Ho mostrato entrambe le versioni .Parse() e .TryParse() qui.

Questo è un esempio di utilizzo:

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

Ed ecco il codice che ti porta lì...

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

Ho creato questo, che ha soddisfatto le mie esigenze (volevo che il mio metodo di estensione emulasse il più vicino possibile il ritorno del TryParse del framework, ma senza blocchi try{} catch{} e senza che il compilatore si lamentasse di inferire un tipo nullable all'interno del metodo 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;
}

Suggerisco il codice qui sotto.Potresti lavorare con un'eccezione, quando si è verificato un errore di conversione.

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

Utilizza questo metodo di estensione nel codice (compila int?Proprietà età di una classe di persone):

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

Mi rendo conto che questo è un vecchio argomento, ma non puoi semplicemente:

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

?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top