TypeDescriptor CanConvertFrom Bug? or i'm doing it wrong?
This is an extension method taken out from http://dnpextensions.codeplex.com/.
I understand that the string "test" isn't a number string...
I understand that the GetConverter(targetType) is of type int...
What I don't understand is why it say it can convert from a string... but it fail...
/// <summary>
/// Converts an object to the specified target type or returns the default value.
/// </summary>
/// <typeparam name = "T"></typeparam>
/// <param name = "value">The value.</param>
/// <param name = "defaultValue">The default value.</param>
/// <returns>The target type</returns>
public static T ConvertTo<T>(this object value, T defaultValue)
{
if (value != null)
{
var targetType = typeof(T);
var valueType = value.GetType();
if (valueType == targetType) return (T)value;
var converter = TypeDescriptor.GetConverter(value);
if (converter != null)
{
if (converter.CanConvertTo(targetType))
return (T)converter.ConvertTo(value, targetType);
}
converter = TypeDescriptor.GetConverter(targetType);
if (converter != null)
{
if (converter.CanConvertFrom(valueType))
return (T)converter.ConvertFrom(value);
}
}
return defaultValue;
}
[TestMethod]
public void TestConvertToWillFail()
{
// Arrange
var value = "test";
// Act
var result = value.ConvertTo<int>();
// Assert
result.Should().Equal(0);
result.Should().Not.Eq开发者_高级运维ual(value);
}
[TestMethod]
public void TestConvertToShouldPass()
{
// Arrange
var value = 123;
var stringValue = "123";
// Act
var stringResult = stringValue.ConvertTo<int>();
// Assert
stringResult.Should().Equal(value);
stringResult.Should().Not.Equal(0);
}
Note: Should() is from Should.codeplex.com
Exception from test:
test is not a valid value for Int32.
What your method is doing in the second call is:
- Get the StringConverter
- Ask it if it can convert to integers - it answers no
- Get the IntegerConverter
- Ask it if it can convert from string - it answers yes
- Ask it to convert the provided value ("test") - and this is where it blows up, since "test" is indeed not a valid value for Int32.
The CanConvertFrom/To
methods are just to verify if the call makes sense at all, not whether the conversion will succeed, since CanConvert
works only on the type level
There are strings that will convert to valid integers, but that does not mean that all strings are valid integers, so ConvertFrom/To
will throw exceptions, even if the CanConvert
return true.
This is my work around. Please let me know if there's a better version of this out there.
/// <summary>
/// Converts an object to the specified target type or returns the default value.
/// </summary>
/// <typeparam name = "T"></typeparam>
/// <param name = "value">The value.</param>
/// <param name = "defaultValue">The default value.</param>
/// <returns>The target type</returns>
public static T ConvertTo<T>(this object value, T defaultValue)
{
if (value != null)
{
try
{
var targetType = typeof(T);
var valueType = value.GetType();
if (valueType == targetType)
return (T)value;
var converter = TypeDescriptor.GetConverter(value);
if (converter != null)
{
if (converter.CanConvertTo(targetType))
return (T)converter.ConvertTo(value, targetType);
}
converter = TypeDescriptor.GetConverter(targetType);
if (converter != null)
{
if (converter.CanConvertFrom(valueType))
{
return (T)converter.ConvertFrom(value);
}
}
}
catch (Exception e)
{
return defaultValue;
}
}
return defaultValue;
}
ConvertTo can throw exceptions if it is not able to perform the conversion... even if CanConvertTo returns true.
e.g. "12" can be converted to an integer but "test" cannot be. However the converter would say that it can convert from string to integer.
精彩评论