我试图从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中用于解决文化问题,等等。
你认为第二种方法更好吗?
我可以用任何方式改进我的代码吗?
答案 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和声明性能优势。