C#string解析为变量类型

Bry*_*ore 1 c#

我想轻松地将一个字符串解析成一个类型,但是我不想为每个类型编写包装器代码,我只是希望能够执行"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&ltint&gt;() == 1234;
    /// "a".Parse&ltint&gt;() == 0;
    /// "a".Parse&ltint?&gt;() == null;
    /// "2010-01-01".Parse&lt;DateTime?&gt;() == new DateTime(2010, 1, 1)
    /// "2010-01-01a".Parse&lt;DateTime?&gt;() == null
    /// "127.0.0.1".Parse&lt;System.Net.IPAddress&gt;().Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }))
    /// "".Parse&lt;System.Net.IPAddress&gt;() == 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&ltint&gt;(-1) == 1234;
    /// "a".Parse&ltint&gt;(-1) == -1;
    /// "2010-01-01".Parse&lt;DateTime?&gt;(new DateTime(1900, 1, 1)) == new DateTime(2010, 1, 1)
    /// "2010-01-01a".Parse&lt;DateTime?&gt;(new DateTime(1900, 1, 1)) == new DateTime(1900, 1, 1)
    /// "127.0.0.1".Parse&lt;System.Net.IPAddress&gt;(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }))
    /// "".Parse&lt;System.Net.IPAddress&gt;(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)

裤子!


Bra*_*don 7

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

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)