C#string解析为变量类型

我想轻松地将一个字符串解析成一个类型,但我不想为每个类型编写包装器代码,我只是想能够执行“1234”.Parse()之类的操作并让它返回1234.应该适用于任何具有解析function的类型。

我的解决方案适用于任何实现静态方法TryParse(string,out T)的类型,无论它是类还是结构。 此外,它将适用于可为空的结构,例如

"1234".Parse() == 1234 "asdf".Parse() == 0 // ie default(int) "1234".Parse() == 1234 "asdf".Parse() == null "2001-02-03".Parse() == new DateTime(2009, 2, 3) 

因为System.Net.IPAddress有TryParse,

 "127.0.0.1".Parse().Equals(new IPAddress(new byte[] { 127, 0, 0, 1 })) 

我使用System.Linq.Expressions框架创建代码,然后缓存创建的lambda。 由于这是在具有指定类型的通用静态类中完成的,因此每种类型只需解析一次。

 public static class StringExtensions { ///  /// Parse the  as a . If this cannot be achieved, return the default value of . ///  /// The type to parse into. /// The string to parse. /// The resultant  or the default of . ///  ///  /// "1234".Parse&ltint>() == 1234; /// "a".Parse&ltint>() == 0; /// "a".Parse&ltint?>() == null; /// "2010-01-01".Parse<DateTime?>() == new DateTime(2010, 1, 1) /// "2010-01-01a".Parse<DateTime?>() == null /// "127.0.0.1".Parse<System.Net.IPAddress>().Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 })) /// "".Parse<System.Net.IPAddress>() == null ///  ///  public static T Parse(this string target) { return ParseHelper.Parse(target); } ///  /// Parse the  as a . If this cannot be achieved, return  ///  /// The type to parse into. /// The string to parse. /// The value to return if  could not be parsed. /// The resultant  or . ///  ///  /// "1234".Parse&ltint>(-1) == 1234; /// "a".Parse&ltint>(-1) == -1; /// "2010-01-01".Parse<DateTime?>(new DateTime(1900, 1, 1)) == new DateTime(2010, 1, 1) /// "2010-01-01a".Parse<DateTime?>(new DateTime(1900, 1, 1)) == new DateTime(1900, 1, 1) /// "127.0.0.1".Parse<System.Net.IPAddress>(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 })) /// "".Parse<System.Net.IPAddress>(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })) ///  ///  public static T Parse(this string target, T defaultValue) { return ParseHelper.Parse(target, defaultValue); } private static class ParseHelper { private static readonly Func _parser; static ParseHelper() { Type type = typeof(T); bool isNullable = false; if (type.GetGenericArguments().Length > 0 && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { isNullable = true; type = type.GetGenericArguments()[0]; } ParameterExpression target = Expression.Parameter(typeof(string), "target"); ParameterExpression defaultValue = Expression.Parameter(typeof(T), "defaultValue"); ParameterExpression result = Expression.Parameter(typeof(T), "result"); if (isNullable) { Type helper = typeof(NullableParseHelper<>); helper = helper.MakeGenericType(typeof(T), type); MethodInfo parseMethod = helper.GetMethod("Parse"); _parser = Expression.Lambda>( Expression.Call(parseMethod, target, defaultValue), target, defaultValue, result).Compile(); } else { MethodInfo tryParseMethod = (from m in typeof(T).GetMethods() where m.Name == "TryParse" let ps = m.GetParameters() where ps.Count() == 2 && ps[0].ParameterType == typeof(string) && ps[1].ParameterType == typeof(T).MakeByRefType() select m).SingleOrDefault(); if (tryParseMethod == null) { throw new InvalidOperationException(string.Format("Cannot find method {0}.TryParse(string, out {0})", type.FullName)); } _parser = Expression.Lambda>( Expression.Condition( Expression.Call(tryParseMethod, target, result), result, defaultValue), target, defaultValue, result).Compile(); } } public static T Parse(string target) { return _parser.Invoke(target, default(T), default(T)); } public static T Parse(string target, T defaultValue) { return _parser.Invoke(target, defaultValue, default(T)); } private static class NullableParseHelper where TBase : struct { private static readonly Func _parser; static NullableParseHelper() { MethodInfo tryParseMethod = (from m in typeof(TBase).GetMethods() where m.Name == "TryParse" let ps = m.GetParameters() where ps.Count() == 2 && ps[0].ParameterType == typeof(string) && ps[1].ParameterType == typeof(TBase).MakeByRefType() select m).SingleOrDefault(); if (tryParseMethod == null) { throw new InvalidOperationException(string.Format("Cannot find method {0}.TryParse(string, out {0})", typeof(TBase).FullName)); } ParameterExpression target = Expression.Parameter(typeof(string), "target"); ParameterExpression defaultValue = Expression.Parameter(typeof(TBase?), "defaultValue"); ParameterExpression result = Expression.Parameter(typeof(TBase), "result"); _parser = Expression.Lambda>( Expression.Condition( Expression.Call(tryParseMethod, target, result), Expression.ConvertChecked(result, typeof(TBase?)), defaultValue), target, defaultValue, result).Compile(); } public static TBase? Parse(string target, TBase? defaultValue) { return _parser.Invoke(target, defaultValue, default(TBase)); } } } } 

裤子!

这个技巧应该有效。 它使用您自动分配的变量类型:

 public static class StringExtensions { public static ParsedString Parse(this string s) { return new ParsedString(s); } } public class ParsedString { string str; public ParsedString(string s) { str = s; } public static implicit operator int(ParsedString s) { return int.Parse(s.str); } public static implicit operator double(ParsedString s) { return double.Parse(s.str); } public static implicit operator short(ParsedString s) { return short.Parse(s.str); } public static implicit operator byte(ParsedString s) { return byte.Parse(s.str); } // ... add other supported types ... } 

用法:

 int p = "1234".Parse(); 

我宁愿使用框架提供的方法显式解析,而不是依赖于这些技巧。

为什么不能使用已有的解析?

 int.Parse("1234"); decimal.Parse("1234"); double.Parse("1234"); 

如果您不确定它是否能够成功解析,请使用TryParse。

或者,如果您想将其实现为扩展方法,请查看本文 , 该文章将向您展示如何创建Generic String.Parse方法。

编辑:在我发布答案后,我不知道该网站如何迅速下降。 这是本文创建的类:

 using System; using System.ComponentModel; public static class Parser { public static T Parse(this string value) { // Get default value for type so if string // is empty then we can return default value. T result = default(T); if (!string.IsNullOrEmpty(value)) { // we are not going to handle exception here // if you need SafeParse then you should create // another method specially for that. TypeConverter tc = TypeDescriptor.GetConverter(typeof(T)); result = (T)tc.ConvertFrom(value); } return result; } } 

例子:

 // regular parsing int i = "123".Parse(); int? inull = "123".Parse(); DateTime d = "01/12/2008".Parse(); DateTime? dn = "01/12/2008".Parse(); // null values string sample = null; int? k = sample.Parse(); // returns null int l = sample.Parse(); // returns 0 DateTime dd = sample.Parse(); // returns 01/01/0001 DateTime? ddn = sample.Parse(); // returns null 

我知道这个问题是四年了,但你仍然可以考虑使用这个:

 public static T Parse(this string target) { Type type = typeof(T); //In case of a nullable type, use the underlaying type: var ReturnType = Nullable.GetUnderlyingType(type) ?? type; try { //in case of a nullable type and the input text is null, return the default value (null) if (ReturnType != type && target == null) return default(T); return (T)Convert.ChangeType(target, ReturnType); } catch { return default(T); } } 

您可以使用一系列.TryParse() if块来执行此操作,但是您将无法使用它,因为此方法必须返回类型object 。 所以在呼叫站点,你只需要在进行任何算术或任何事情之前尝试投射它。

您可以编写一个包装函数,为您要支持的每种类型调用tryParse

这种情况有两个问题。 首先,您必须编写一些代码来分析字符串,以尝试确定可以解析的数据类型,然后选择其中一种逻辑。 (例如,字符串“1”可以解析为byte,sbyte,int,uint,long,ulong,float,double和Decimal。更糟糕的是,字符串“4.8.12”可以解析为几种数字类型以及DateTime以三种不同的方式导致完全不同的值……)

另一个问题是,任何能够执行此操作的方法都必须返回对象中的装箱值,因此您仍需要为每种数据类型设置包装器代码,以便取消装箱值。

此外,如果您无法控制类型,您会怎么做? 所以,不要试图让这更简单,它只会变得更复杂。