我想轻松地将一个字符串解析成一个类型,但是我不想为每个类型编写包装器代码,我只是希望能够执行"1234".Parse()之类的操作并让它返回1234.应该适用于任何具有解析功能的类型.
这个技巧应该有效.它使用您自动分配的变量类型:
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();
我宁愿使用框架提供的方法显式解析,而不是依赖于这些技巧.
我的解决方案适用于任何实现静态方法TryParse(string,out T)的类型,无论它是类还是结构.此外,它将适用于可以为空的结构,例如
"1234".Parse() == 1234 "asdf".Parse () == 0 // i.e. 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 . /// public static T Parse/// "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 ///
///(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 ifcould not be parsed. /// The resultant ///or . /// public static T Parse/// "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 })) ///
///(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)); } } } }
裤子!
为什么不能使用已有的解析?
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