Как разбирать строку в nullable int

Я хочу разобрать строку в nullable int в С#. то есть. Я хочу вернуть либо значение 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;
        }
    }
}   

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

EDIT: Спасибо за предложения TryParse, я об этом знал, но это сработало примерно так же. Мне больше интересно узнать, есть ли встроенный метод framework, который будет анализировать непосредственно в nullable int?

Ответ 1

int.TryParse, вероятно, немного проще:

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

Изменить @Glenn int.TryParse встроен в структуру. Это и int.Parse - способ разбора строк в ints.

Ответ 2

Вы можете сделать это в одной строке, используя условный оператор и тот факт, что вы можете применить null к типу с нулевым значением (две строки, если у вас нет предварительно существующего int, вы можете повторно использовать для вывода of TryParse):

Pre С# 7:

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

С обновленным синтаксисом С# 7, который позволяет объявлять выходную переменную в вызове метода, становится еще проще.

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

Ответ 3

У меня была эта проблема, с которой я столкнулся (в конце концов, return if и 2 слишком длинное!):

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

На более серьезном замечании, старайтесь не смешивать int, который является ключевым словом С#, с Int32, который является типом .NET Framework BCL - хотя он работает, он просто делает код неопрятным.

Ответ 4

Glenn Slaven: меня больше интересует знание того, существует встроенный структурный метод который будет анализироваться непосредственно в nullable int?

Существует такой подход, который будет анализироваться непосредственно с помощью nullable int (а не только int), если значение действительно как нулевая или пустая строка, но делает исключение для недопустимых значений, поэтому вам нужно будет поймать исключение и вернуть значение по умолчанию для этих ситуаций:

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

Этот подход все еще можно использовать для не-нулевых анализов, а также с нулевым значением:

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: В конвертере вы можете использовать метод IsValid вместо захвата исключения (заброшенные исключения приводят к ненужным накладные расходы, если ожидается). К сожалению, он работает только с .NET 4, но по-прежнему существует проблема, когда он не проверяет ваш язык при проверке правильных форматов DateTime, см. ошибка 93559.

Ответ 5

Попробуйте следующее:

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

Ответ 6

Старая тема, но как насчет:

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

Мне нравится это лучше, поскольку requriement, где разобрать нуль, версия TryParse не будет вызывать ошибку, например. ToNullableInt32 (XXX). Это может привести к нежелательным молчащим ошибкам.

Ответ 7

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

Источники:

Ответ 8

Я считаю, что мое решение - очень чистое и приятное решение:

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

Это, конечно, общее решение, которое требует только, чтобы аргумент generics имел статический метод "Parse (string)". Это работает для чисел, boolean, DateTime и т.д.

Ответ 9

Вы можете забыть все остальные ответы - есть большое общее решение: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

Это позволяет писать очень чистый код следующим образом:

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

а также:

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

Ответ 10

Следующее должно работать для любого типа структуры. Он основан на кодексе Matt Manela из форумов MSDN. Как отмечает Мерф, обработка исключений может быть дорогостоящей по сравнению с использованием метода 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;
        }

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

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

Ответ 11

Я бы предложил следующие методы расширения для разбора строки в значение int с возможностью определения значения по умолчанию, если разбор невозможен:

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

Ответ 12

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

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

Ответ 13

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

Нет.

Ответ 14

Я нашел и адаптировал некоторый код для универсального класса 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;
        }
    }
}

Ответ 15

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

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

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 и т.д.

Ответ 16

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

Ответ 17

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

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

Ответ 18

Используя делегатов, следующий код может предоставить возможность повторного использования, если вам понадобится нулевой синтаксический анализ для нескольких типов структуры. Я показал здесь варианты .Parse() и .TryParse().

Это пример использования:

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

И вот код, который доставит вас туда...

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

Ответ 19

Я придумал этот, который удовлетворил мои требования (я хотел, чтобы мой метод расширения эмулировал как можно ближе возврат структуры TryParse, но без try {} catch {} блоков и без компилятора, жалующегося о выводе типа NULL в рамках метода структуры)

private static bool TryParseNullableInt(this string s, out int? result)
{
    int i;
    result = int.TryParse(s, out i) ? (int?)i : null;
    return result != null;
}

Ответ 20

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

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

ИЛИ

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

Ответ 21

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

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

?