通用TryParse扩展方法

时间:2009-10-31 16:33:59

标签: c# generics

代码来自here

我想听听有关此扩展方法的一些专家意见。我打算使用它,但想知道我可能遇到的任何已知问题。

我最好在初级类型上使用TryParse方法吗?

public static T? TryParse<T>(this object obj) where T : struct
        {
            if (obj == null) return null;

            T? result = null;
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
            if (converter != null)
            {
                try
                {
                    string str = obj.ToString();
                    result = (T)converter.ConvertFromString(str);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            return result;
        }

5 个答案:

答案 0 :(得分:25)

TryParse模式最好遵循标准模式,允许与非结构一起使用:

public static bool TryParse<T>(string s, out T value) {
    TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
    try {
        value = (T) converter.ConvertFromString(s);
        return true;
    } catch {
        value = default(T);
        return false;
    }
}

注意我在这里接受了string,因为这是TryParse最常见的意思;否则,Convert.ChangeType可能更合适。

我认为没有理由将其作为扩展方法(根据问题示例中的this),当然不宜过多地污染object扩展方法。

答案 1 :(得分:4)

以下扩展程序可能对您有用。它们适用于任何具有Parse或TryParse方法的类型......

他们来自我的扩展程序库: http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

虽然这个项目可能有点过时了......我必须更新它作为某些观点:-D

希望这有帮助!

public static class StringExtensions
    {
        public static TOut ParseOrDefault<TOut>(this string input)
        {
            return input.ParseOrDefault(default(TOut));
        }
        public static TOut ParseOrDefault<TOut>(this string input, TOut defaultValue)
        {
            Type type = typeof(TOut);
            MethodInfo parseMethod = type.GetMethod("Parse", new Type[] { typeof(string) });

            if (parseMethod != null)
            {
                var value = parseMethod.Invoke(null, new string[] { input });
                return (value is TOut ? (TOut)value : defaultValue);
            }
            else { return defaultValue; }
        }
        public static bool TryParseOrDefault<TOut>(this string input, out TOut output)
        {
            return input.TryParseOrDefault(out output, default(TOut));
        }
        public static bool TryParseOrDefault<TOut>(this string input, out TOut output, TOut defaultValue)
        {
            output = defaultValue;

            Type type = typeof(TOut);
            MethodInfo parseMethod = type.GetMethod(
                "TryParse",
                new Type[] { typeof(string), typeof(TOut).MakeByRefType() });

            if (parseMethod != null)
            {
                object[] parameters = new object[] { input, output };
                var value = parseMethod.Invoke(null, parameters);

                if (value is bool)
                {
                    bool successful = (bool)value;
                    if (successful)
                    {
                        output = (TOut)parameters[1];
                        return true;
                    }
                }
            }
            return false;
        }
    }

答案 2 :(得分:3)

当您想要改变方法或类的公共合同时,泛型是最有用的,并且方法或类的内部并不真正关心(或关心)变化的类型。

一些例子:

List<T>是一个可以放入内容的集合,而且内部的类并不关心(很多)该类型的内容。

T System.Linq.Enumerable.First<T>(IEnumerable<T> source)返回一堆元素中的第一个元素。这种方法不需要在内部知道什么类型才能完成工作。

相比之下,解析方法必须根据结果的类型更改其行为。在提供的方法中,有策略将行为推送到其他方法,但是该选择存在运行时成本。

另一种方法是让调用者(必须知道Type或他们不能用它调用泛型方法),选择转换器。这种选择可以在设计时或编译时进行,因此会产生0运行时成本。

旁注:请不要使用重新抛出一切成语。它只是重置调用堆栈,你不想这样做。

catch (Exception ex)
{
  throw ex;
}

答案 3 :(得分:3)

对于更简单的代码,您可以这样做:

T value = (T)Convert.ChangeType(value, typeof(T));

https://stackoverflow.com/a/1465930/24315感谢Thomas Levesque。

答案 4 :(得分:1)

如果性能有问题,它会使用反射,因此可能会很慢。