开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜