I am trying to convert from a String a a generic type. The generic type will be an Int32, Int64, Boolean, Double and so on ... I tried two approaches:
public static Boolean TryParse<T>(String source, out T value) {
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
try {
value = (T)converter.ConvertFromString(source);
return true;
} catch {
value = default(T);
return false;
}
}
public static Boolean TryChangeType<T>(Object source, out T value) {
try {
Type type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
value = (T)Convert.ChangeType(source, type);
return true;
} catch {
value = default(T);
return false;
}
}
The second one is more generic as it accepts an Object.
I am also considering passing an IFormatProvider in TryChangeType that would be used in Convert.ChangeType to resolve Culture issues and so on.
Do you consider the second approach better?
Any way I can improve my code?
ChangeType(Object, TypeCode) is a general-purpose conversion method that converts the object specified by value to a predefined type specified by typeCode . The value parameter can be an object of any type.
Try: Type type = Type. GetType(inputString); //target type object o = Activator.
Provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties.
In the first example of yours you can get rid of the try catch block by calling CanConvertTo()
and CanConvertFrom()
beforehand.
public static bool TryParse<T>(string source, out T value)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof (T));
if (converter.CanConvertTo(typeof (T)) && converter.CanConvertFrom(typeof (string)))
{
value = (T)converter.ConvertFromString(source);
return true;
}
else
{
value = default (T);
return false;
}
}
In the second example why not make it even more generic and pass in a generic type?
Convert
only works if the type implements the interface IConvertible so you can check for that, on the other hand it stil doesn't ensure that the conversion will be possible.
public static bool TryChangeType<T, TR>(T input, out TR output) where T : IConvertible
{
bool result = false;
try
{
Type type = Nullable.GetUnderlyingType(typeof(TR));
output = (TR)Convert.ChangeType(input, type);
result = true;
}
catch(Exception)
{
output = default(TR);
}
return result;
}
It would be nice to only catch the exceptions you know of:
catch(InvalidCastException)
{
output = default(TR);
//Conversion is not unsupported
}
catch(FormatException)
{
output = default(TR);
//string input value was in incorrect format
}
catch(InvalidCastException)
{
output = default(TR);
//Conversion is not unsupported
}
catch(OverflowException)
{
output = default(TR);
//narrowing conversion between two numeric types results in loss of data
}
This might not answer the question fully, but you were asking for possible improvements so I thought why not.
The second one is applicable only for IConvertible
types. If this is what you want, you might want to apply a constraint, too (ChangeType
will throw an exception for non-convertible types anyway):
public static Boolean TryChangeType<T>(Object source, out T value)
where T : IConvertible
{
// ...
}
The first one is more general, TypeConverter
is used when the .NET component model should be used. For example, in designers, type converters are used to convert the values from string in the property grid. But you should add a small additional check here, too:
if (!converter.CanConvertFrom(typeof(string)))
return false;
Additionally, I would mention that you should use the ConvertFromInvariantString
method if you do not want trouble with the different region settings (in case of floating point values, for example)...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With