测试Convert.ChangeType是否适用于两种类型

jer*_*enh 27 c# reflection

这是关于使用反射转换值的问题的后续行动.将某种类型的对象转换为另一种类型可以这样做:

object convertedValue = Convert.ChangeType(value, targetType);
Run Code Online (Sandbox Code Playgroud)

给定两个Type实例(比如FromType和ToType),有没有办法测试转换是否成功?

我可以写一个像这样的扩展方法:

public static class TypeExtensions
{
    public static bool CanChangeType(this Type fromType, Type toType)
    {
        // what to put here?
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:这就是我现在所拥有的.丑陋,但我还没有看到另一种方式......

bool CanChangeType(Type sourceType, Type targetType)
{
  try
  {
    var instanceOfSourceType = Activator.CreateInstance(sourceType);
    Convert.ChangeType(instanceOfSourceType, targetType);
    return true; // OK, it can be converted
  }
  catch (Exception ex)
  {
    return false;
  }
Run Code Online (Sandbox Code Playgroud)

esa*_*sac 32

我刚刚遇到同样的问题,我使用Reflector来查看ChangeType的源代码.ChangeType在3种情况下抛出异常:

  1. conversionType为null
  2. value为null
  3. 值不实现IConvertible

检查完3个后,保证可以转换.因此,您可以通过简单地自行检查这3个内容来节省大量性能并删除try {}/catch {}块:

public static bool CanChangeType(object value, Type conversionType)
{
    if (conversionType == null)
    {
        return false;
    }

    if (value == null)
    {              
        return false;
    }

    IConvertible convertible = value as IConvertible;

    if (convertible == null)
    {
        return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,它仍然可以抛出InvalidCastException.似乎你无法预先检查这一点.如果IConvertible有一个CanConvertToType方法会很好. (32认同)
  • 对象实现IConvertible这一事实并不意味着它可以将自身转换为任何类型.例如,System.Int32实现IConvertible,但我不确定是否可以将任何Int32转换为类AfricanLanguage的对象 (5认同)
  • 还可能发生其他异常 - 如果两种类型通常“兼容”,但源值不适合目标;例如。Convert.ChangeType(double.MaxValue, typeof(int)) 将抛出 OverflowException。 (2认同)

Mar*_*tke 8

检查反射器中的Convert.ChangeType方法我在静态构造函数中找到了这个:

ConvertTypes = new Type[] { 
        typeof(Empty), typeof(object), typeof(DBNull), typeof(bool), typeof(char), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal), 
        typeof(DateTime), typeof(object), typeof(string)
     };
Run Code Online (Sandbox Code Playgroud)

最后,此方法只是检查源是否正在实现IConvertible,或者目标是否是上面的ConvertTypes之一.所以你的方法应该看起来像这样(非常粗糙):

return (ConvertTypes.Contains(toType) || typeof(IConvertible).IsAssignableFrom(fromType));
Run Code Online (Sandbox Code Playgroud)

  • 与我在上面的评论中提到的相似.不幸的是,检查`Type`实现`IConvertible`是不够的.仍然无法保证任何尝试的转换实际上都会成功. (4认同)