I am trying to write a generic Parse method that converts and returns a strongly typed value from a NamedValueCollection. I tried two methods but both of these methods are going through boxing and unboxing to get the value. Does anyone know a way to avoid the boxing? If you saw this in production would you not like it, how bad is it for performance?
Usuage:
var id = Request.QueryString.Parse<int>('id');
Attempt #1:
public static T Parse<T>(this NameValueCollection col, string key) { string value = col[key]; if (string.IsNullOrEmpty(value)) return default(T); if (typeof(T) == typeof(int)) { //return int.Parse(value); // cannot convert int to T //return (T)int.Parse(value); // cannot convert int to T return (T)(object)int.Parse(value); // works but boxes } if (typeof(T) == typeof(long)) { return (T)(object)long.Parse(value); // works but boxes } ... return default(T); }
Attempt #2 (using reflection):
public static T Parse<T>(this NameValueCollection col, string key) { string value = col[key]; if (string.IsNullOrEmpty(value)) return default(T); try { var parseMethod = typeof(T).GetMethod('Parse', new Type[] { typeof(string) }); if (parseMethod == null) return default(T); // still boxing because invoke returns an object var parsedVal = parseMethod.Invoke(null, new object[] { value }); return (T)parsedVal; } // No Proper Parse Method found catch(AmbiguousMatchException) { } return default(T); }
I think you are over estimating the impact of the boxing/unboxing. The parse method will have a much bigger overhead (string parsing), dwarfing the boxing overhead. Also all the if statements will have a bigger impact. Reflection has the biggest impact of all.
I’d would not like to see this kind of code in production, as there is a cleaner way of doing it. The major problem I have with it is the large number of if statements you will need to cover all cases and the fact that someone could pass any old type to it.
What I would do is write a parse function for each type I want to parse (ie ParseInt()). It’s clearer and it is well defined what the function will try to do. Also with short static methods, the compiler is more likely to inline them, saving a function call.
I think this is a bad application of generics, any particular reason for doing it this way?