I have been playing around with converting a string to a value type in .NET, where the resulting value type is unknown. The problem I have encountered in my code is that I need a method which accepts a string, and uses a "best fit" approach to populate the resulting value type. Should the mechanism not find a suitable match, the string is returned.
This is what I have come up with:
public static dynamic ConvertToType(string value)
{
Type[] types = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
foreach (Type type in types)
{
try
{
return Convert.ChangeType(value, type);
}
catch (Exception)
{
continue;
}
}
return value;
}
I feel that this approach is probably not best practice because it can only match against the predefined types.
Usually I have found that .NET accommodates this functionality in a better way than my implementation, so my question is: are there any better approaches to this problem and/or is this functionality implemented better in .NET?
EDIT: Note that the ordering of types in the array is so that the "best fit" occurs as accurately as possible for the given types.
EDIT: as per miniBill's request, this I how the method might be used (simple example!):
JsonDictionary["myKey"] = ConvertToType("255"); // 255 is a stringified json value, which should be assigned to myKey as a byte.
Your method isn't ideal as its going to cause a series of exceptions if value is not a SByte.
Seeing as all of these types share a common method .TryParse(string, out T) we can use reflection extract the method and call it for each type. I made the method an extension method on string and also factored out the Type[] array into its own lazy loaded property for faster use.
public static class StringExtensions
{
public static dynamic ConvertToType(this string value)
{
foreach (Type type in ConvertibleTypes)
{
var obj = Activator.CreateInstance(type);
var methodParameterTypes = new Type[] { typeof(string), type.MakeByRefType() };
var method = type.GetMethod("TryParse", methodParameterTypes);
var methodParameters = new object[] { value, obj };
bool success = (bool)method.Invoke(null, methodParameters);
if (success)
{
return methodParameters[1];
}
}
return value;
}
private static Type[] _convertibleTypes = null;
private static Type[] ConvertibleTypes
{
get
{
if (_convertibleTypes == null)
{
_convertibleTypes = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
}
return _convertibleTypes;
}
}
}
Usage:
string value = "2391203921";
dynamic converted = value.ConvertToType();
Your approach would work but, as you say, it's not that elegant.
I think you have a couple of ways to improve this code:
Move the array out of the function, as psubsee2003 said
Use the TryParse methods for cheaper testing (no catching involved) (e.g.: Int32.TryParse)
Actually write a parser that, after trimming,
Checks if the number is a GUID
Does it have '-' in it at a position > 0?
if(Guid.TryParse)
return result
return string (it can't be a number!)
Checks if the number is fractional (does it have a dot in it?)
Tries to convert to single, double, decimal using the various TryParse
If it fails return string
Does it start with a minus?
Try and parse as Int64, then check size and see where if fits (<256 -> ubyte, < 65536 ushort...)
If it fails return string
Try and parse as Int64
If it works check minimum size it fits into
If it fails it could be an integer, but too big, try parsing as double, if it fails return string
This is something I wrote previously that might be a help:
public static Boolean CanCovertTo(this String value, Type type)
{
var targetType = type.IsNullableType() ? Nullable.GetUnderlyingType(type) : type;
TypeConverter converter = TypeDescriptor.GetConverter(targetType);
return converter.IsValid(value);
}
The basic idea is if you pass the string and a Type that you want to test, you can check if a conversion will be valid before attempting to covert.
The problem with this design is that TypeConverter.IsValid() is just a wrapper (with some exception handling) for TypeConverter.CanConvertFrom() so you really aren't eliminating the exception handling, but since it is part of the BCL, I tend to think that is going to be a better implementation.
So you can implement this like so:
private static Type[] defaultTypes = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
public static dynamic ConvertToType(string value)
{
return ConvertToType(value, defaultTypes);
}
public static dynamic ConvertToType(string value, Type[] types)
{
foreach (Type type in types)
{
if (!value.CanConvertTo(type))
continue;
return Convert.ChangeType(value, type);
}
return value;
}
There is not really a great way to do this without the exception handling (even the exception handling in the TypeConverter.IsValid method), so you have to live with it if you really need such a method. But you can limit the need for the exception handling if you implement some of the suggestions in miniBill's answer in addition to some improvements in the design.
You could use Reflection to handle all the Parse types by calling the TryParse method, this will be a bit faster than handling multiple exceptions using ChangeType
public Type[] PredefinedTypes = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
public dynamic ConvertToType(string value)
{
foreach (var predefinedType in PredefinedTypes.Where(t => t.GetMethods().Any(m => m.Name.Equals("TryParse"))))
{
var typeInstance = Activator.CreateInstance(predefinedType);
var methodParamTypes = new Type[] { typeof(string), predefinedType.MakeByRefType() };
var methodArgs = new object[] { value, typeInstance };
if ((bool)predefinedType.GetMethod("TryParse", methodParamTypes).Invoke(predefinedType, methodArgs))
{
return methodArgs[1];
}
}
return value
}
Related
It was just another day with .NET. Until I had to get generic method of a static class with a generic parameter, using reflection for serialization. Doesn't sound so bad. GetRuntimeMethod("x", new[] { type }), as usual should do the trick, or so I thought.
Now, this method keeps returning null for the following variant:
public static Surrogate<T> BuildSurrogate<T>(List<T> collection).
So, a quick copy to LinqPad, and a GetRuntimeMethods run later, it seemed to have all the methods as expected. Naturally, I thought perhaps, something wasn't right with the behavior of GetRuntimeMethod, so, I whipped up a quick extension, GetRuntimeMethodEx that iterates through, and to my surprise, it failed. What? How could that fail. GetRuntimeMethods has the exact the methodInfo I need.
So, I ended up breaking up the extension into parts to understand what exactly is going on, as in the code below. And it turns out (cType != cGivenType) always ended up true.
But a quick inspection, shows they were the same 'apparent' type - List<T>. Now being utterly confused, a diff on the dump of the two typeof(List<T>), and it turns out they were not the same!
The MetadataToken of the two were exactly the same. However the RuntimeTypeHandle were different. The given type had the correct AssemblyQualifiedName, and FullName, belonging to System.Collections.Generic.List``1, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089. Great. But oddly enough, the type on the generic method, had both of them as "null"! So, basically, the List<T> is a magical type with no corresponding assembly(!?). It exists, but doesn't. How fascinating!
Here's a quick dump of the diff between the two, that's relevant.
Note the GenericTypeParameters, and IsGenericTypeDefinition - They are the ones which seem to make perfect sense. The oddities aside, now how could one create a Type that matches this type on the MethodInfo? Potentially, the compiler expects a generic type of List<> with the generic parameter T - The only problem is, you can't literally make a generic type with T. The T has to be a type of something, which now invalidates the equality.
private void Main()
{
var type = typeof (List<>);
var m = typeof (Builders).GetRuntimeMethods();
var surrogateBuilder = typeof (Builders)
.GetRuntimeMethodEx("BuildSurrogate", new[] {type});
}
static class Builders
{
public static Surrogate<T> BuildSurrogate<T>(List<T> collection)
{
return new Surrogate<T>
{
Items = collection.ToArray(),
};
}
public class Surrogate<T>
{
public IEnumerable<T> Items;
}
}
public static class ReflectionExtensions
{
public static MethodInfo GetRuntimeMethodEx(
this Type type, string name, params Type[] types)
{
var m = type.GetRuntimeMethods();
var res = (m.Where(t =>
{
var n = name;
return t.Name.Equals(n);
}).FirstOrDefault(t =>
{
var px = t.GetParameters().ToArray();
var currentTypes = px.Select(p => p.ParameterType).ToArray();
if (currentTypes.Length < 1) return false;
for (var i = 0; i < types.Length; i++)
{
var cGivenType = types[i];
for (var j = 0; j < currentTypes.Length; j++)
{
var cType = currentTypes[j];
if (cType != cGivenType) return false;
}
}
return true;
}));
return res;
}
}
That's because your type is a GenericTypeDefinition (List<>) and the one taken from reflecting your class is an actual List<T>.
Your code is not readable, so I wrote my own from scratch. The important part is in TypesMatch method.
public static MethodInfo GetRuntimeMethodEx(
this Type type, string name, params Type[] types)
{
var withMatchingParamTypes =
from m in type.GetRuntimeMethods()
where m.Name == name
let parameterTypes = m.GetParameters().Select(p => p.ParameterType).ToArray()
where parameterTypes.Length == types.Length
let pairs = parameterTypes.Zip(types, (actual, expected) => new {actual, expected})
where pairs.All(x => TypesMatch(x.actual, x.expected))
select m;
return withMatchingParamTypes.FirstOrDefault();
}
private static bool TypesMatch(Type actual, Type expected)
{
if (actual == expected)
return true;
if (actual.IsGenericType && expected.IsGenericTypeDefinition)
return actual.GetGenericTypeDefinition() == expected;
return false;
}
Returns your method, as expected.
You can't create a Type instance that represents List<T> with unknown T. That's what GetGenericTypeDefinition and List<> are for.
I'm working on building a dynamic calculation framework, that will build a generic GUI based on the calculation types and attributes on those types.
For instance, I might have a simple Adder calculator (forgive the simplicity, but when putting together frameworks, I like to start simple and work my way up), that looks like this:
[CalculatorAttribute("This calculator add X+Y=Z")]
class AdderCalculator : CalculatorBase
{
[CalculationValueAttribute(InputOutputEnum.InputValue, "First Input")]
public int? X
{
set { m_X = value; m_Z = null;}
get { return m_X; }
}
[CalculationValueAttribute(InputOutputEnum.InputValue, "Second Input")]
public int? Y
{
set{ m_Y = value; m_Z = null;}
get { return m_Y; }
}
[CalculationValueAttribute(InputOutputEnum.OutputValue, "Output")]
public int? Z
{
get { return m_Z; }
}
public AdderCalculator()
{
m_X = m_Y = m_Z = null;
}
public override Boolean ReadyToCalc()
{
return (m_X != null && m_Y != null);
}
public override Boolean NeedToCalc()
{
return (m_Z == null);
}
public override void Calculate()
{
if(ReadyToCalc()){ m_Z = m_X + m_Y;}
}
private int? m_X, m_Y, m_Z;
}
(forgive the whitespace, I tried to reduce the size as much as possible without sacrificing too much readability).
I'm using the nullable type to allow me to distinguish unset values from set values
Now, in my GUI, I'm using TextBoxes to collect the input information. From TextBox, I can only get the Text (String). Using reflection, I know the name of the property and can get it's setter (set_X or set_Y in this case).
The type of the field is (of course) int? (nullable int), but I can use:
PropertyInfo.PropertyType.GetGenericArguments();
method to get the Int32 type (or Int64, whichever may be the case).
So, given that I can end up with a instance of a Type object, can anyone recommend a generic way to convert String to that type
What I have considered is:
Implement a string setter method in my AdderCalculator: set_X(String s)
Change my control type to NumericUpDown, as it will return a Decimal
change the type to Decimal, but Decimal can't directly convert from String either (it can use parse, but that is tougher from a generic standpoint
Can anyone provide additional insight?
Just to get the answer out where it can be clearly seen, the code I ended up with is:
// collect relevant inputs
foreach (Control c in fPanelIn.Controls)
{
if (c.Tag is PropertyInfo)
{
PropertyInfo pi = c.Tag as PropertyInfo;
if(c.Text.Length>0)
{
Type ti = pi.PropertyType;
if (ti.IsGenericType)
{
ti = ti.GetGenericArguments()[0];
}
object o = Convert.ChangeType(c.Text, ti);
pi.SetValue(Calculator, o, null);
//MethodInfo mi = calcType.GetMethod(ConstructMethodName(pi), new Type[] { typeof(String) });
//mi.Invoke(Calculator, new object[] { c.Text });
}
else
{
pi.SetValue(Calculator, null, null);
}
}
}
I still need to add some exception protection for invalid values, but this works with the property type being any numeric type (byte, short, int, int32, int64, float, double, Decimal, etc...)
Is there any way to have a method return any one of a number of generic types from a method? For example, I have the following:
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
if(typeof(T) == typeof(Int32))
{
return Int32.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(Double))
{
return Double.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(String))
{
return element.Attribute(attribute).Value;
}
if(typeof(T) == typeof(ItemLookupType))
{
return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
}
}
(This is only a very quick mockup, I'm aware that any production code would need to be significantly more thorough in null checks etc...)
But the compiler doesn't like it, complaining that Int32 cannot be implicitly converted to T (it doesn't work with a cast either). I can understand that. At compile time it has no way to know what T is, but I'm checking it beforehand. Is there anyway I can make this work?
I've done these types of generic methods in the past. The easiest way to get type inference is to provide a generic converter function.
public static T ParseAttributeValue<T>
(this XElement element, string attribute, Func<string, T> converter)
{
string value = element.Attribute(attribute).Value;
if (String.IsNullOrWhiteSpace(value)) {
return default(T);
}
return converter(value);
}
You can use it like the following:
int index = element.ParseAttributeValue("index", Convert.ToInt32);
double price = element.ParseAttributeValue("price", Convert.ToDouble);
You can even provide your own functions and have all the fun in the world (even return anonymous types):
ItemLookupType lookupType = element.ParseAttributeValue("lookupType",
value => Enum.Parse(typeof(ItemLookupType), value));
var item = element.ParseAttributeValue("items",
value => {
List<string> items = new List<string>();
items.AddRange(value.Split(new [] { ',' }));
return items;
});
.Net already has a bunch of great string conversion routines you can use! A TypeConverter can do most of the heavy lifting for you. Then you don't have to worry providing your own parsing implementations for built-in types.
Note that there are locale-aware versions of the APIs on TypeConverter that could be used if you need to handle parsing values expressed in different cultures.
The following code will parse values using the default culture:
using System.ComponentModel;
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string)))
{
string value = element.Attribute(attribute).Value;
return (T)converter.ConvertFromString(value);
}
return default(T);
}
This will work for a lot of built-in types, and you can decorate custom types with a TypeConverterAttribute to allow them to participate in the type conversion game too. This means that in the future you will be able to parse new types without having to change the implementation of the ParseAttributeValue.
see: http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx
Why are you using the type parameter as the return type at all? This would work, just requires a cast after calling:
public static Object ParseAttributeValue<T>(this XElement element, string attribute)
{
if(typeof(T) == typeof(Int32))
{
return Int32.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(Double))
{
return Double.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(String))
{
return element.Attribute(attribute).Value;
}
if(typeof(T) == typeof(ItemLookupType))
{
return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
}
}
Or better yet:
public static Int32 ParseAsInt32(this XElement element, string attribute)
{
return Int32.Parse(element.Attribute(attribute).Value);
}
// etc, repeat for each type
This second approach has the additional benefit of having a much higher likelihood of getting inlined, plus it will (for value types like Int32) prevent the need to box/unbox the value. Both of these will cause the method to perform somewhat faster.
Not sure if this is exactly what you want, but you can make the returns work if you cast to object first then to T
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
if (typeof(T) == typeof(Int32))
{
return (T)(object)Int32.Parse(element.Attribute(attribute).Value);
}
if (typeof(T) == typeof(Double))
{
return (T)(object)Double.Parse(element.Attribute(attribute).Value);
}
if (typeof(T) == typeof(String))
{
return (T)(object)element.Attribute(attribute).Value;
}
return default(T);
}
However you still have to provide T at compile time, calling the method like:
int value = element.ParseAttributeValue<int>("attribute");
Here's two ways of doing it...
static T ReadSetting<T>(string value)
{
object valueObj = null;
if (typeof(T) == typeof(Int32))
valueObj = Int32.Parse(value);
return (T)valueObj;
}
static dynamic ReadSetting2<T>(string value)
{
if (typeof(T) == typeof(Int32))
return Int32.Parse(value);
throw new UnsupportedException("Type is unsupported");
}
static void Main(string[] args)
{
int val1 = ReadSetting<Int32>("2");
int val2 = ReadSetting2<Int32>("3");
}
With C++ templates, this kind of thing would work, but only if each piece of code were in a different, separate specialization. The thing that makes that work is that unused function templates are not compiled (or more accurately: not fully instantiated), so the fact that a piece of code would be invalid if that copy of the template were instantiated with a different type doesn't come up.
C# is different, and AFAIK there's no specialization for generics. One way to accomplish what you are trying to do, while working within the limitations of C# would be to create one function with a more abstract return type, and use the ParseAttributeValue only to cast it to T.
So you would have:
private static Object AbstractParseValue(System.Type t, XElement element, string attribute)
and
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
return (T)AbstractParseValue(typeof(T), element, attribute);
}
I would suggest that rather than testing the type parameter every time the routine is executed, you should create a generic static class something like this:
internal static class ElementParser<T>
{
public static Func<XElement, string, T> Convert = InitConvert;
T DefaultConvert(XElement element, string attribute)
{
return Default(T); // Or maybe throw exception, or whatever
}
T InitConvert(XElement element, string attribute)
{
if (ElementParser<int>.Convert == ElementParser<int>.InitConvert)
{ // First time here for any type at all
Convert = DefaultConvert; // May overwrite this assignment below
ElementParser<int>.Convert =
(XElement element, string attribute) =>
Int32.Parse(element.Attribute(attribute).Value);
ElementParser<double>.Convert =
(XElement element, string attribute) =>
Int32.Parse(element.Attribute(attribute).Value);
// etc. for other types
}
else // We've done other types, but not this type, and we don't do anything nice for it
{
Convert = DefaultConvert;
}
return Convert(element, attribute);
}
}
public static T ParseAttributeValue(this XElement element, string attribute)
{
ElementParser<T>.Convert(element, attribute);
}
Using this approach, one will only have to do special handling the first time a particular type is used. After that, the conversion can be performed using only a single generic delegate invocation. Once could easily add any number of types, and even allow converters to be registered for any desired type at runtime.
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;
}
}
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;
}
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.
It uses reflection and thus may be slow, if performance is an issue.
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);
}
public static T Parse<T>(this NameValueCollection col, string key)
{
return (T)Convert.ChangeType(col[key], typeof(T));
}
I'm not entirely sure of ChangeType boxes or not (I guess reading the docs would tell me, but I'm pressed for time right now), but at least it gets rid of all that type-checking. The boxing overhead is not very high, though, so I wouldn't worry too much about it. If you're worried about run-time type consistency, I'd write the function as:
public static T Parse<T>(this NameValueCollection col, string key)
{
T value;
try
{
value = (T)Convert.ChangeType(col[key], typeof(T));
}
catch
{
value = default(T);
}
return value;
}
This way the function won't bomb if the value cannot be converted for whatever reason. That means, of course, that you'll have to check the returned value (which you'd have to do anyway since the user can edit the querystring).
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?
I'll add a little undocumented way:
public static T Convert<T>()
{
if (typeof(T) == typeof(int))
{
int a = 5;
T value = __refvalue(__makeref(a), T);
return value;
}
else if (typeof(T) == typeof(long))
{
long a = 6;
T value = __refvalue(__makeref(a), T);
return value;
}
throw new NotImplementedException();
}
There is little documentation about them, but they work as of C# 4.0. Read for example here Hidden Features of C#? Remember that undocumented means unsupported, blah blah blah could not work in the future blah blah blah if you use them the devil will come for you blah blah blah :-)
For better readability, you could use a generic dictionary with an anonymous function as follows:
var parserFuncs = new Dictionary<Type, Func<string, object>>() {
{ typeof(int), p => (int) int.Parse(p) },
{ typeof(bool), p => (bool) bool.Parse(p) },
{ typeof(long), p => (long) long.Parse(p) },
{ typeof(short), p => (short) short.Parse(p) },
{ typeof(DateTime), p => (DateTime) DateTime.Parse(p) }
/* ...same for all the other primitive types */
};
return (T) parserFuncs[typeof(T)](value);
Another suggestion for implementation, using a TryParse or Parse method with a generic approach. I wrote this originally to convert strings parsed from a csv file into different types, int, decimal, list, etc.
public static bool TryParse<T>(this string value, out T newValue, T defaultValue = default(T))
where T : struct, IConvertible
{
newValue = defaultValue;
try
{
newValue = (T)Convert.ChangeType(value, typeof(T));
}
catch
{
return false;
}
return true;
}
public static T Parse<T>(this string value)
where T : struct, IConvertible
{
return (T) Convert.ChangeType(value, typeof (T));
}
Here, the try parse method first sets the newValue to the default value, then tries to convert value to type T and return the newValue as type T. If the conversion fails, it returns the default value of T.
The Parse method, simply tries to do the conversion, however if its not fail safe and will throw an exception if the conversion fails.
Am I too late?
static Dictionary<Type, Delegate> table =
new Dictionary<Type, Delegate>{
{ typeof(int), (Func<string,int>)Int32.Parse },
{ typeof(double), (Func<string,double>)Double.Parse },
// ... as many as you want
};
static T Parse<T>(string str)
{
if (!table.TryGet(typeof(T), out Delegate func))
throw new ArgumentException();
var typedFunc = (Func<string, T>)func;
return typedFunc(str);
}
When in trouble with types, try delegates and dicts!
int value = int.Parse(Request.QueryString["RecordID"]);
Here's a suggestion for implementation, following Robert Wagner's logic, but using a generic approach to reduce duplication:
public static int ParseInt32(this NameValueCollection col, string key)
{
return Parse(col, key, int.Parse);
}
public static double ParseDouble(this NameValueCollection col, string key)
{
return Parse(col, key, double.Parse);
}
private static T Parse<T>(NameValueCollection col, string key, Func<string, T> parse)
{
string value = col[key];
if (string.IsNullOrEmpty(value))
return default(T);
return parse(value);
}
Truth be told, returning zero for a null or empty string scares me; this could cause problems if some values are legitimately zero. Instead, I would have the methods return nullables (int?, double?, etc.), which is a slightly more compact approach than the out-parameter pattern used for the framework TryParse methods. You could do this:
public static int? ParseInt32(this NameValueCollection col, string key)
{
return Parse(col, key, int.Parse);
}
public static double? ParseDouble(this NameValueCollection col, string key)
{
return Parse(col, key, double.Parse);
}
private static T? Parse<T>(NameValueCollection col, string key, Func<string, T> parse)
where T : struct
{
string value = col[key];
if (string.IsNullOrEmpty(value))
return default(T?);
return parse(value);
}
But that would still throw an exception for non-null-or-empty strings that aren't numeric. It's better to use TryParse. The built-in Func delegates don't support ref or out parameters, so you'd have to declare your own delegate type, but that is fairly trivial.