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<int>() == 1234; /// "a".Parse<int>() == 0; /// "a".Parse<int?>() == 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<int>(-1) == 1234; /// "a".Parse<int>(-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以三种不同的方式导致完全不同的值……)
另一个问题是,任何能够执行此操作的方法都必须返回对象中的装箱值,因此您仍需要为每种数据类型设置包装器代码,以便取消装箱值。
此外,如果您无法控制类型,您会怎么做? 所以,不要试图让这更简单,它只会变得更复杂。