Как разобрать строку в обнуляемый int - PullRequest
278 голосов
/ 05 сентября 2008

Я хочу разобрать строку в обнуляемый int в C #. то есть. Я хочу вернуть либо значение int строки, либо null, если оно не может быть проанализировано.

Я надеялся, что это сработает

int? val = stringVal as int?;

Но это не сработает, поэтому, как я это делаю сейчас, я написал этот метод расширения

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

Есть ли лучший способ сделать это?

РЕДАКТИРОВАТЬ: Спасибо за предложения TryParse, я знал об этом, но это сработало примерно так же. Мне больше интересно знать, есть ли встроенный метод фреймворка, который будет анализировать напрямую в обнуляемый тип int?

Ответы [ 21 ]

3 голосов
/ 09 апреля 2010

Следующее должно работать для любого типа структуры. Он основан на коде Мэтта Манелы с форумов MSDN . Как указывает Мёрф, обработка исключений может быть дорогой по сравнению с использованием метода TryParse, выделенного для Types.

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

Это были базовые тестовые примеры, которые я использовал.

        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);
2 голосов
/ 19 ноября 2013

Это решение является общим без дополнительных затрат.

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);
}
1 голос
/ 08 октября 2015
    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 голос
/ 24 марта 2011

Я чувствовал, что должен поделиться своим, что более обобщенно.

Использование:

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

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

Решение:

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

Первая версия медленнее, так как требует попытки, но выглядит чище. Если он не будет вызываться много раз с неверными строками, это не так важно. Если производительность является проблемой, обратите внимание, что при использовании методов TryParse вам необходимо указать параметр типа ParseBy, так как он не может быть выведен компилятором. Мне также пришлось определить делегат, так как ключевое слово out нельзя использовать в Func <>, но по крайней мере на этот раз компилятору не требуется явный экземпляр.

Наконец, вы можете использовать его и с другими структурами, например, десятичными, DateTime, Guid и т. Д.

1 голос
/ 28 октября 2008

Мне больше интересно знать, есть ли встроенный метод фреймворка, который будет анализировать напрямую в обнуляемый тип int?

Нет.

1 голос
/ 23 октября 2009

Я нашел и адаптировал некоторый код для класса Generic NullableParser. Полный код в моем блоге 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;
        }
    }
}
0 голосов
/ 10 ноября 2015

Я предлагаю код ниже. Вы можете работать с исключением, когда произошла ошибка преобразования.

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

Используйте этот метод расширения в коде (заполните int? Свойство Age класса person):

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

OR

AgeTextBox.Text.TryParse(i => person.Age = i, exc => { MessageBox.Show(exc.Message); });
0 голосов
/ 20 марта 2015

Я пришел с этим, который удовлетворил мои требования (я хотел, чтобы мой метод расширения как можно ближе эмулировал возвращение TryParse фреймворка, но без блоков try {} catch {} и без жалоб компилятора о выводе обнуляемого типа в методе 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;
}
0 голосов
/ 05 сентября 2008

Вы должны никогда использовать исключение, если вам не нужно - накладные расходы ужасны.

Варианты TryParse решают проблему - если вы хотите проявить творческий подход (чтобы ваш код выглядел более элегантно), вы, вероятно, могли бы что-то сделать с методом расширения в 3.5, но код был бы более или менее таким же. *

0 голосов
/ 11 марта 2010

Я понимаю, что это старая тема, но вы не можете просто:

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

...