14

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;
        }
2
  • 5
    As answers have said, don't throw ex. You rarely, if ever, want to do that. Just throw. Commented Oct 31, 2009 at 19:53
  • 4
    It also defeats the point of a Try if you throw the exception... Commented Oct 31, 2009 at 19:55

5 Answers 5

28

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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

1 Comment

Oops...I didn't see how old the post was! LOL. Sorry about that.
3

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

2 Comments

1 motivation for using this generic method is reduce calling client code vs using primative parsers. You are right that clients knows the runtime types but they but they must also handle exceptions. Also, can u link me on more info re resetiing stack trace? Thanks
And, you could get the client to pass you the parser (as a Func<T, U> if nothing else), instead of the type - that would avoid the reflection.
3

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.

Comments

1

It uses reflection and thus may be slow, if performance is an issue.

Comments