我想轻松地将一个字符串解析成一个类型,但是我不想为每个类型编写包装器代码,我只是希望能够执行"1234".Parse()之类的操作并让它返回1234.应该适用于任何具有解析功能的类型.
Meh*_*ari 21
这个技巧应该有效.它使用您自动分配的变量类型:
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 ...
}
Run Code Online (Sandbox Code Playgroud)
用法:
int p = "1234".Parse();
Run Code Online (Sandbox Code Playgroud)
我宁愿使用框架提供的方法显式解析,而不是依赖于这些技巧.
ckk*_*ght 16
我的解决方案适用于任何实现静态方法TryParse(string,out T)的类型,无论它是类还是结构.此外,它将适用于可以为空的结构,例如
"1234".Parse<int>() == 1234
"asdf".Parse<int>() == 0 // i.e. default(int)
"1234".Parse<int?>() == 1234
"asdf".Parse<int?>() == null
"2001-02-03".Parse<DateTime?>() == new DateTime(2009, 2, 3)
Run Code Online (Sandbox Code Playgroud)
因为System.Net.IPAddress有TryParse,
"127.0.0.1".Parse<IPAddress>().Equals(new IPAddress(new byte[] { 127, 0, 0, 1 }))
Run Code Online (Sandbox Code Playgroud)
我使用System.Linq.Expressions框架创建代码,然后缓存创建的lambda.由于这是在具有指定类型的通用静态类中完成的,因此每种类型只需解析一次.
public static class StringExtensions
{
/// <summary>
/// Parse the <paramref name="target"/> as a <typeparamref name="T"/>. If this cannot be achieved, return the default value of <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type to parse into.</typeparam>
/// <param name="target">The string to parse.</param>
/// <returns>The resultant <typeparamref name="T"/> or the default of <typeparamref name="T"/>.</returns>
/// <example>
/// <code>
/// "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
/// </code>
/// </example>
public static T Parse<T>(this string target)
{
return ParseHelper<T>.Parse(target);
}
/// <summary>
/// Parse the <paramref name="target"/> as a <typeparamref name="T"/>. If this cannot be achieved, return <paramref name="defaultValue"/>
/// </summary>
/// <typeparam name="T">The type to parse into.</typeparam>
/// <param name="target">The string to parse.</param>
/// <param name="defaultValue">The value to return if <paramref name="target"/> could not be parsed.</param>
/// <returns>The resultant <typeparamref name="T"/> or <paramref name="defaultValue"/>.</returns>
/// <example>
/// <code>
/// "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 }))
/// </code>
/// </example>
public static T Parse<T>(this string target, T defaultValue)
{
return ParseHelper<T>.Parse(target, defaultValue);
}
private static class ParseHelper<T>
{
private static readonly Func<string, T, T, T> _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<Func<string, T, T, T>>(
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<Func<string, T, T, T>>(
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<TBase> where TBase : struct
{
private static readonly Func<string, TBase?, TBase, TBase?> _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<Func<string, TBase?, TBase, TBase?>>(
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));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
裤子!
为什么不能使用已有的解析?
int.Parse("1234");
decimal.Parse("1234");
double.Parse("1234");
Run Code Online (Sandbox Code Playgroud)
如果您不确定它是否能够成功解析,请使用TryParse.
或者,如果您想将其实现为扩展方法,请查看本文,该文章将向您展示如何创建Generic String.Parse方法.
编辑:在我发布答案后,我不知道该网站如何迅速下降.这是本文创建的类:
using System;
using System.ComponentModel;
public static class Parser {
public static T Parse<T>(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;
}
}
Run Code Online (Sandbox Code Playgroud)
例子:
// regular parsing
int i = "123".Parse<int>();
int? inull = "123".Parse<int?>();
DateTime d = "01/12/2008".Parse<DateTime>();
DateTime? dn = "01/12/2008".Parse<DateTime?>();
// null values
string sample = null;
int? k = sample.Parse<int?>(); // returns null
int l = sample.Parse<int>(); // returns 0
DateTime dd = sample.Parse<DateTime>(); // returns 01/01/0001
DateTime? ddn = sample.Parse<DateTime?>(); // returns null
Run Code Online (Sandbox Code Playgroud)