适用于所有数据类型的动态 TryParse

问题描述 投票:0回答:3

我需要检查一个对象是否可以转换为特定的数据类型,并提出了这个:

public static bool TryParseAll(System.Type typeToConvert, object valueToConvert)
{

    bool succeed = false;

    switch (typeToConvert.Name.ToUpper())
    {
        case "DOUBLE":
            double d;
            succeed = double.TryParse(valueToConvert.ToString(), out d);
            break;
        case "DATETIME":
            DateTime dt;
            succeed = DateTime.TryParse(valueToConvert.ToString(), out dt);
            break;
        case "INT16":
            Int16 i16;
            succeed = Int16.TryParse(valueToConvert.ToString(), out i16);
            break;
        case "INT":
            Int32 i32;
            succeed = Int32.TryParse(valueToConvert.ToString(), out i32);
            break;
        case "INT32":
            Int32 i322;
            succeed = Int32.TryParse(valueToConvert.ToString(), out i322);
            break;
        case "INT64":
            Int64 i64;
            succeed = Int64.TryParse(valueToConvert.ToString(), out i64);
            break;
        case "BOOLEAN":
            bool b;
            succeed = Boolean.TryParse(valueToConvert.ToString(), out b);
            break;
        case "BOOL":
            bool b1;
            succeed = bool.TryParse(valueToConvert.ToString(), out b1);
            break;
    }

    return succeed;
}

我想知道除了这个还有其他方法吗?哪个更有活力、更高效?

谢谢!

c# types converters tryparse
3个回答
5
投票

您应该使用 TypeDescriptor 类:

public static T Convert<T>(this string input)
{
    var converter = TypeDescriptor.GetConverter(typeof(T));
    if(converter != null)
    {
        //Cast ConvertFromString(string text) : object to (T)
        return (T)converter.ConvertFromString(input);
    }
    return default(T);
}

当然,如果转换失败,这会抛出异常,因此您需要尝试/捕获它。


3
投票

这是我的通用

TryParse
方法的版本。 我相信你也可以使用这个版本:

double pi;
if(ValueTypeHelper.TryParse("3.14159", out pi)) {
    // .. pi = 3.14159
}
...
string eStr = "2.71828";
float e;
if(eStr.TryParse(out e)) {
    // .. e = 2.71828f
}
...
static class ValueTypeHelper {
    static IDictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>();
    public static bool TryParse<T>(this string valueStr, out T result) {
        Delegate d = null;
        if(!cache.TryGetValue(typeof(T), out d)) {
            var mInfos = typeof(T).GetMember("TryParse", MemberTypes.Method, BindingFlags.Static | BindingFlags.Public);
            if(mInfos.Length > 0) {
                var s = Expression.Parameter(typeof(string));
                var r = Expression.Parameter(typeof(T).MakeByRefType());
                d = Expression.Lambda<TryParseDelegate<T>>(
                    Expression.Call(mInfos[0] as MethodInfo, s, r), s, r).Compile();
            }
            cache.Add(typeof(T), d);
        }
        result = default(T);
        TryParseDelegate<T> tryParse = d as TryParseDelegate<T>;
        return (tryParse != null) && tryParse(valueStr, out result);
    }
    delegate bool TryParseDelegate<T>(string valueStr, out T result);
}

更新:这是一个更“现代”且线程安全的版本

static class ValueTypeHelper {
    static ConcurrentDictionary<Type, Delegate> cache = new ConcurrentDictionary<Type, Delegate>();
    public static bool TryParse<T>(this string valueStr, out T result) {
        var tryParse = cache.GetOrAdd(typeof(T), t => {
            // find method with static bool TryParse(string s, out T result) signature
            var parameterTypes = new Type[] { typeof(string), typeof(T).MakeByRefType() };
            var mInfo_TryParse = t.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null);
            if(mInfo_TryParse != null) {
                // Build method dynamically
                var s = Expression.Parameter(parameterTypes[0]);
                var result = Expression.Parameter(parameterTypes[1]);
                return Expression.Lambda<TryParseDelegate<T>>(
                    Expression.Call(mInfo_TryParse, s, result), s, result).Compile();
            }
            return null;
        }) as TryParseDelegate<T>;
        if(tryParse == null) {
            result = default(T);
            return false;
        }
        return tryParse(valueStr, out result);
    }
    delegate bool TryParseDelegate<T>(string valueStr, out T result);
}

1
投票

我结合了 DmitryG 和 RezaRahmati 的建议解决方案:

static class GenericValueConverter
{
    public static bool TryParse<T>(this string input, out T result)
    {
        bool isConversionSuccessful = false;
        result = default(T);

        var converter = TypeDescriptor.GetConverter(typeof(T));
        if (converter != null)
        {
            try
            {
                result = (T)converter.ConvertFromString(input);
                isConversionSuccessful = true;
            }
            catch { }
        }

        return isConversionSuccessful;
    }
}

void Main()
{
    double pi;
    if (GenericValueConverter.TryParse("3,14159", out pi)) //Use right decimal point seperator for local culture
    {
        pi.Dump(); //ConsoleWriteline for LinqPad
        //pi=3,14159
    }

    string dtStr = "2016-12-21T16:34:22";
    DateTime dt;
    if (dtStr.TryParse(out dt))
    {
        dt.Dump(); //ConsoleWriteline for LinqPad
        //dt=21.12.2016 16:34:22
    }

    string guidStr = "D430831B-03B0-44D5-A971-4E73AF96B5DF";
    Guid guid;
    if (guidStr.TryParse(out guid))
    {
        guid.Dump(); //ConsoleWriteline for LinqPad
        //guid=d430831b-03b0-44d5-a971-4e73af96b5df
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.