如何将一个stringparsing为一个可空的int
我想要在C#中将stringparsing为可空的int。 即。 我想要返回string的int值,如果无法parsing,则返回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的build议,我知道这一点,但它的工作大致相同。 我更有兴趣知道是否有一个内置的框架方法,将直接parsing到一个可空的int?
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
是parsingstring的方法。
你可以在一行中使用条件运算符,也可以将null
转换为可为null的types(如果没有预先存在的int,可以重复使用TryParse
的输出):
Pre C#7:
int tempVal; int? val = Int32.TryParse(stringVal, out unused) ? Int32.Parse(s) : (int?)null;
使用C#7的更新语法,您可以在方法调用中声明输出variables,这变得更加简单。
int? val = Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null;
对不起,无法抗拒 – 有这个问题,谷歌把我带到这里,但我最终与此(毕竟, 如果和2 回报是太啰嗦!):
int? ParseNInt (string val) { int i; return int.TryParse (val, out i) ? (int?) i : null; }
更严重的是,尽量不要将int (C#关键字)和Int32 (它是一个.NET Framework BCLtypes)混合在一起,尽pipe它起作用,但它使代码看起来很乱。
Glenn Slaven :我更感兴趣的是知道是否有内置的框架方法可以直接parsing为一个可空的int?
有这种方法,将直接parsing为一个可为空的int(而不仅仅是int),如果该值是有效的,如null或空string,但会抛出无效值的exception,因此您将需要捕获exception并返回默认值对于这些情况:
public static T Parse<T>(object value) { try { return (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.ToString()); } catch { return default(T); } }
这种方法仍然可以用于非空的parsing以及可空的:
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%");
注意:可以使用转换器上的IsValid方法,而不是捕获exception(如果需要,抛出的exception确实会导致不必要的开销 )。 不幸的是,它只适用于.NET 4以后,但在validation正确的DateTime格式时,它仍然没有检查您的语言环境,请参阅bug 93559 。
尝试这个:
public static int? ParseNullableInt(this string value) { int intValue; if (int.TryParse(value, out intValue)) return intValue; return null; }
你可以忘记所有其他的答案 – 有一个很好的通用解决scheme: 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();
老话题,但如何:
public static int? ParseToNullableInt(this string value) { return String.IsNullOrEmpty(value) ? null : (int.Parse(value) as int?); }
我更喜欢这个parsingnull的需求,TryParse版本不会在例如ToNullableInt32(XXX)上抛出一个错误。 这可能会导致不需要的安静错误。
以下应该适用于任何结构types。 它基于MSDN论坛的Matt Manela的代码。 正如Murph指出,与使用Types专用的TryParse方法相比,exception处理可能会很昂贵。
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; }
这些是我使用的基本testing案例。
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);
我觉得我的解决scheme是一个非常干净和漂亮的解决scheme
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; } }
这当然是一个通用的解决scheme,只需要generics参数有一个静态方法“Parse(string)”。 这适用于数字,布尔值,date时间等。
该解决scheme是通用的,没有reflection开销
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); }
我更有兴趣知道是否有一个内置的框架方法,将直接parsing到一个可空的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,但看起来更干净。 如果用无效的string不会多次调用它,那就不重要了。 如果性能是一个问题,请注意当使用TryParse方法时,您需要指定ParseBy的types参数,因为编译器无法推断它。 我还必须定义一个委托为out关键字不能在Func <>内使用,但至less这次编译器不需要一个显式的实例。
最后,还可以将其与其他结构一起使用,即小数,date时间,Guid等。
我find并修改了一个genericsNullableParser类的代码。 完整的代码在我的博客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的返回,但没有尝试{} catch {}块,没有编译器抱怨推断框架方法内的可空types)
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; }
如果你不需要,你永远不应该使用exception – 开销太可怕了。
TryParse上的变体解决了这个问题 – 如果你想创造性(使你的代码看起来更优雅),你可以用3.5中的扩展方法做一些事情,但是代码会差不多。
使用委托,如果您发现自己需要多个结构types的可空分析,下面的代码才能提供可重用性。 我已经在这里显示了.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)); } }
我build议下面的代码。 当发生转换错误时,您可能会使用exception。
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); } }
在代码中使用此扩展方法(填充人类类的年龄属性):
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); });
我意识到这是一个古老的话题,但你不能简单地:
(Nullable<int>)int.Parse(stringVal);
?