代码之家  ›  专栏  ›  技术社区  ›  jeroenh

测试Convert.ChangeType是否在两种类型之间工作

  •  27
  • jeroenh  · 技术社区  · 15 年前

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

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

    给定两个类型实例(例如FromType和ToType),是否有方法测试转换是否成功?

    例如,我可以写这样的扩展方法吗:

    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 回复  |  直到 6 年前
        1
  •  31
  •   Edward Brey    6 年前

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

    1. ConversionType为空
    2. 值为空
    3. 值不实现IConvertable

    在检查完这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;
    }
    
        2
  •  8
  •   Marc Wittke    15 年前

    检查Reflector中的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));
    
        3
  •  1
  •   skolima    12 年前

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

    它包括根据以下内容转换值的能力:

    • 可想象的
    • 类型转换器
    • ToXxx方法
    • 分析静态方法
    • 参数化构造函数
    • 还有一些小的

    Data Type Conversions

        4
  •  0
  •   Immac    6 年前

    基于这两个问题的答案,我提出了这个问题(需要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启动所有可能的属性。