Как разобрать строку в nullable int
Я хочу разобрать строку в nullable 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;
}
}
}
есть ли лучший способ сделать это?
EDIT: Спасибо за предложения TryParse, я знал об этом, но получилось примерно то же самое. Мне больше интересно узнать, есть ли встроенный метод фреймворка, который будет анализировать непосредственно в nullable int?
20 ответов:
int.TryParse- пожалуй, немного проще:public static int? ToNullableInt(this string s) { int i; if (int.TryParse(s, out i)) return i; return null; }Edit @Glenn
int.TryParse"встроен в фреймворк". Это иint.Parseare the способ разбора строк на ints.
вы можете сделать это в одной строке, используя условный оператор и тот факт, что вы можете бросить
nullк типу nullable (две строки, Если у вас нет уже существующего int, вы можете повторно использовать для выводаTryParse):Pre C#7:
int tempVal; int? val = Int32.TryParse(stringVal, out tempVal) ? Int32.Parse(stringVal) : (int?)null;с обновленным синтаксисом C#7, который позволяет объявлять выходную переменную в вызове метода, это становится еще проще.
int? val = Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null;
извините, не мог удержаться-была эта проблема, и Google привел меня сюда, но я закончил с этим (в конце концов,Если и 2 returns-это Су многословный!):
int? ParseNInt (string val) { int i; return int.TryParse (val, out i) ? (int?) i : null; }на более серьезной ноте, старайтесь не смешивать int, что является ключевым словом C#, с int32 значение, который является типом BCL .NET Framework-хотя он работает,он просто делает код грязным.
Гленн Билич: мне больше интересно узнать, если есть встроенный рамочный метод что будет разбирать непосредственно в nullable int?
существует такой подход, который будет анализировать непосредственно на nullable int (а не только int), если значение допустимо, как null или пустая строка, но создает исключение для недопустимых значений, поэтому вам нужно будет поймать исключение и вернуть значение по умолчанию для тех ситуации:
public static T Parse<T>(object value) { try { return (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.ToString()); } catch { return default(T); } }этот подход все еще может быть использован для ненулевых разборов, а также для 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: в преобразователе есть метод IsValid, который вы можете использовать вместо захвата исключения (брошенные исключения приводят к ненужные накладные расходы если ожидается). К сожалению, он работает только с .NET 4, но все еще есть проблема, когда он не проверяет вашу локаль при проверке правильных форматов DateTime, см. ошибка 93559.
попробуйте это:
public static int? ParseNullableInt(this string value) { int intValue; if (int.TryParse(value, out intValue)) return intValue; return null; }
старая тема, но как насчет:
public static int? ParseToNullableInt(this string value) { return String.IsNullOrEmpty(value) ? null : (int.Parse(value) as int?); }мне это больше нравится как requriement, где для разбора null, версия TryParse не будет выдавать ошибку, например, ToNullableInt32(XXX). Это может привести к нежелательным молчаливым ошибкам.
Я чувствую, что мое решение является очень чистым и приятным решением:
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)". Это работает для чисел, булевых, DateTime и т. д.
вы можете забыть все другие ответы - есть отличное общее решение: 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();
следующее должно работать для любого типа структуры. Он основан на коде от Мэтт Манела из форумов MSDN. Как указывает Murph, обработка исключений может быть дорогостоящей по сравнению с использованием метода 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; }Это были основные тестовые случаи, которые я использовал.
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);
Это решение является общим без отражения накладных расходов.
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); }
меня больше интересует, есть ли встроенный метод фреймворка, который будет анализировать непосредственно в nullable int?
нет.
Я чувствовал, что должен поделиться своим, который является немного более общим.
использование:
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; } }первая версия медленнее, так как она требует try-catch, но она выглядит чище. Если он не будет вызываться много раз с недопустимыми строками, это не так важно. Если производительность является проблемой, обратите внимание, что при использовании методов TryParse необходимо указать параметр типа ParseBy, поскольку он не может быть выведен компилятором. Мне тоже пришлось определить делегат как ключевое слово out нельзя использовать в Func, но по крайней мере на этот раз компилятор не требует явного экземпляра.
наконец, вы можете использовать его и с другими структурами, т. е. decimal, DateTime, Guid и т. д.
Я нашел и адаптировал некоторый код для общего класса 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; } } }
Я придумал этот, который удовлетворил мои требования (я хотел, чтобы мой метод расширения эмулировал как можно ближе возврат TryParse фреймворка, но без блоков try{} catch{} и без компилятора, жалующегося на вывод типа nullable в методе фреймворка)
private static bool TryParseNullableInt(this string s, out int? result) { int i; result = int.TryParse(s, out i) ? (int?)i : null; return result != null; }
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; }
Я бы предложил следующие методы расширения для разбора строк в значение 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(); }
вы должны никогда используйте исключение, если вам не нужно - накладные расходы ужасны.
вариации на TryParse решают проблему - если вы хотите стать творческим (чтобы ваш код выглядел более элегантно), вы, вероятно, могли бы сделать что-то с методом расширения в 3.5, но код будет более или менее одинаковым.
используя делегаты, следующий код может обеспечить возможность повторного использования, если вам понадобится синтаксический анализ с нулевым значением для более чем одного типа структуры. Я показал как .Синтаксический анализ и. 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)); } }
Я предлагаю код ниже. Вы можете работать с исключением, когда произошла ошибка преобразования.
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? Возраст свойство класса человека):
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); });
Comments