简体   繁体   中英

Generic TryParse Extension method

Code taken from here

I would like to hear some expert opinions on this extension method. I do plan to use it, but would like to hear about any known problems i may face.

Am i better of using on primative types TryParse methods?

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;
        }

The TryParse pattern is best following the standard pattern, which allows use with non-structs, too:

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;
    }
}

Note I've accepted a string here, because that is what me most commonly mean by TryParse ; otherwise, Convert.ChangeType might be more appropriate.

I see no reason for this to be an extension method (as per this in the question's example), and certainly it is inadvisable to pollute object with too many extension methods.

The extensions below might be useful to you. They work on any type that has a Parse or TryParse method...

They come from my Extensions library here: http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

Although that project is probably a bit out-of-date...I'll have to update it as some point :-D

Hope this helps!

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;
        }
    }

For simpler code, you can do this:

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

Credit to Thomas Levesque at https://stackoverflow.com/a/1465930/24315 .

Generics are most useful when you want to vary the public contract of a method or class, and the internals of the method or class don't really care (or care much) about the type that varies.

Some examples:

List<T> is a collection you can put things in, and internally the class doesn't care (much) about what that type is.

T System.Linq.Enumerable.First<T>(IEnumerable<T> source) returns the first element out of a bunch of elements. This method doesn't need to know internally what type that is in order to get the job done.

By contrast, a parsing method must change its behavior based on the type of the result. In the supplied method, there is Strategy which pushes the behaviors out to other methods, but there is a runtime cost for that choice.

The alternative is to let the caller (who must know the Type or they couldn't call the generic method with it), pick the converter. This choice is able to be made at design time or compile time and so incurs 0 runtime cost.

Side Note: Please don't use the re-throw everything idiom. All it does is reset the call stack and you don't ever want to do that.

catch (Exception ex)
{
  throw ex;
}

如果性能是一个问题,它使用反射,因此可能很慢。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM