Test if Convert.ChangeType will work between two types

后端 未结 4 1156
悲哀的现实
悲哀的现实 2020-12-03 13:44

This is a follow-up to this question about converting values with reflection. Converting an object of a certain type to another type can be done like this:

o         


        
相关标签:
4条回答
  • 2020-12-03 14:05

    I was just encountering this same issue, and I used Reflector to look at the source for ChangeType. ChangeType throws exceptions in 3 cases:

    1. conversionType is null
    2. value is null
    3. value does not implement IConvertible

    After those 3 are checked, it is guaranteed that it can be converted. So you can save a lot of performance and remove the try{}/catch{} block by simply checking those 3 things yourself:

    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;
    }
    
    0 讨论(0)
  • 2020-12-03 14:06

    I have written a little framework that includes a Convert class that can do more than the System.Convert class. If you are interested in using it, you can download it from Github. It doesn't have the ability to determine if you can convert between values, but that seems like a good feature to add.

    It does include the ability to convert values based on:

    • IConvertible
    • TypeConverters
    • ToXxx methods
    • Parse static methods
    • Parameterized constructor
    • and a few other minor ones

    Data Type Conversions

    0 讨论(0)
  • 2020-12-03 14:10

    Based on what has already been answered on both questions I came up with this, (needs 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;
        }
    }
    

    Production code example:

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

    This starts all properties possible with 0.

    0 讨论(0)
  • 2020-12-03 14:13

    Checking the method Convert.ChangeType in reflector I found this in the static constructor:

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

    In the end, this method is just checking either if the source is implementing IConvertible or if the target is one of the ConvertTypes above. So your method should look something like this (very rough):

    return (ConvertTypes.Contains(toType) || typeof(IConvertible).IsAssignableFrom(fromType));
    
    0 讨论(0)
提交回复
热议问题