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

时间:2009-09-09 12:04:19

标签: c# reflection

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

object convertedValue = Convert.ChangeType(value, targetType);

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

E.g。我可以写一个像这样的扩展方法:

public static class TypeExtensions
{
    public static bool CanChangeType(this Type fromType, Type toType)
    {
        // what to put here?
    }
}
编辑:这就是我现在所拥有的。丑陋,但我还没有看到另一种方式...

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

4 个答案:

答案 0 :(得分:31)

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

  1. conversionType为空
  2. value为null
  3. 值未实现IConvertible
  4. 检查完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;
    }
    

答案 1 :(得分: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)
     };

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

return (ConvertTypes.Contains(toType) || typeof(IConvertible).IsAssignableFrom(fromType));

答案 2 :(得分:1)

我编写了一个包含Convert类的小框架,它可以比System.Convert类做更多。如果您有兴趣使用它,可以从Github下载。它无法确定您是否可以在值之间进行转换,但这似乎是一个很好的添加功能。

它包括基于以下内容转换值的功能:

  • IConvertible
  • 类型转换器
  • ToXxx方法
  • 解析静态方法
  • 参数化构造函数
  • 和其他一些小的

Data Type Conversions

答案 3 :(得分:0)

根据我在这两个问题上已经回答的问题,我想出了这个问题,(需要c#7)

public static object ChangeType(object value, Type conversion)
    {
        var type = conversion;

        if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        {
            if (value == null)
            {
                return null;
            }

            type = Nullable.GetUnderlyingType(type);
        }

        return Convert.ChangeType(value, type);
    }

public static (bool IsSuccess, object Value) TryChangeType(object value, Type conversionType)
    {
        (bool IsSuccess, object Value) response = (false, null);
        var isNotConvertible = 
            conversionType == null 
                || value == null 
                || !(value is IConvertible)
            || !(value.GetType() == conversionType);
        if (isNotConvertible)
        {
            return response;
        }
        try
        {
            response = (true, ChangeType(value, conversionType));
        }
        catch (Exception)
        {
            response.Value = null;
        }

        return response;
    }
}

生产代码示例:

public Item()
    {
        foreach (var pinfo in GetType().GetProperties())
        {
            object value = 0;
            var response = ReflectionHelpers.TryChangeType(value, pinfo.PropertyType);
            if(response.IsSuccess)
            {
                pinfo.SetValue(this, response.Value);
            }
        }
    }

这将以0开始所有可能的属性。