How can I determine if an implicit cast exists in C#?

后端 未结 3 1456
予麋鹿
予麋鹿 2021-02-18 13:16

I have two types, T and U, and I want to know whether an implicit cast operator is defined from T to U.

I\'m aware of the existence of IsAssignableFrom, and this is not

3条回答
  •  死守一世寂寞
    2021-02-18 14:07

    I ended up handling the primitive types scenario manually. Not very elegant, but it works.

    I've also added additional logic to handle nullable types and enums.

    I reused Poke's code for the user-defined type scenario.

    public class AvailableCastChecker
    {
        public static bool CanCast(Type from, Type to)
        {
            if (from.IsAssignableFrom(to))
            {
                return true;
            }
            if (HasImplicitConversion(from, from, to)|| HasImplicitConversion(to, from, to))
            {
                return true;
            }
            List list;
            if (ImplicitNumericConversions.TryGetValue(from, out list))
            {
                if (list.Contains(to))
                    return true;
            }
    
            if (to.IsEnum)
            {
                return CanCast(from, Enum.GetUnderlyingType(to));
            }
            if (Nullable.GetUnderlyingType(to) != null)
            {
                return CanCast(from, Nullable.GetUnderlyingType(to));
            }
    
            return false;
        }
    
        // https://msdn.microsoft.com/en-us/library/y5b434w4.aspx
        static Dictionary> ImplicitNumericConversions = new Dictionary>();
    
        static AvailableCastChecker()
        {
            ImplicitNumericConversions.Add(typeof(sbyte), new List {typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(byte), new List { typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(short), new List {  typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(ushort), new List { typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(int), new List { typeof(long), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(uint), new List { typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(long), new List { typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(char), new List { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
            ImplicitNumericConversions.Add(typeof(float), new List { typeof(double) });
            ImplicitNumericConversions.Add(typeof(ulong), new List { typeof(float), typeof(double), typeof(decimal) });
        }
    
        static bool HasImplicitConversion(Type definedOn, Type baseType, Type targetType)
        {
            return definedOn.GetMethods(BindingFlags.Public | BindingFlags.Static)
                .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType)
                .Any(mi =>
                {
                    ParameterInfo pi = mi.GetParameters().FirstOrDefault();
                    return pi != null && pi.ParameterType == baseType;
                });
    
        }
    }
    

提交回复
热议问题