通用类型转换器 - TypeConverter或Convert.ChangeType

时间:2016-06-24 10:58:55

标签: c#

我试图从String转换为泛型类型。泛型类型将是Int32,Int64,Boolean,Double等......我尝试了两种方法:

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;

  }

}

第二个更通用,因为它接受一个Object。

我也在考虑在TryChangeType中传递一个IFormatProvider,它将在Convert.ChangeType中用于解决文化问题,等等。

你认为第二种方法更好吗?

我可以用任何方式改进我的代码吗?

3 个答案:

答案 0 :(得分:4)

在你的第一个例子中,你可以事先调用CanConvertTo()CanConvertFrom()来摆脱try catch块。

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;
    }
}

在第二个例子中,为什么不使它更通用并传入泛型类型?

Convert仅在类型实现接口IConvertible时才有效,因此您可以检查它,另一方面它stil不能确保转换是可能的。

        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;
    }

仅捕获您所知道的例外情况会很好:

            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
        }

这可能无法完全回答这个问题,但你要求可能的改进,所以我想为什么不这样做。

答案 1 :(得分:1)

第二个仅适用于IConvertible类型。如果这是您想要的,您可能也想要应用约束(ChangeType将为不可转换类型抛出异常):

public static Boolean TryChangeType<T>(Object source, out T value)
    where T : IConvertible
{
    // ...
}

第一个更通用,在使用.NET组件模型时使用TypeConverter。例如,在设计器中,类型转换器用于转换属性网格中字符串的值。但是你也应该在这里添加一个小额外的支票:

if (!converter.CanConvertFrom(typeof(string)))
    return false;

此外,如果您不想使用不同的区域设置(例如浮点值),我会提到您应该使用ConvertFromInvariantString方法...

答案 2 :(得分:0)

在您的第一个示例中,TypeDescriptor.GetConverter(Type)可以抛出异常,因此将其移到try块中。如果不亲自尝试,我会喜欢第二种方法。

This post显示了一个测试可转换性的示例,没有try / catch和声明性能优势。

相关问题