public static bool IsAssignableFrom(TypeOnStack type1, TypeOnStack type2) { // voids aren't assignable if (type1.IsVoid || type2.IsVoid) { return(false); } // wildcards match *everything* if (type1 == TypeOnStack.Get <WildcardType>() || type2 == TypeOnStack.Get <WildcardType>()) { return(true); } if (type1.IsArray && type2.IsArray) { if (type1.Type.GetArrayRank() == type2.Type.GetArrayRank()) { var t1Elem = type1.Type.GetElementType(); var t2Elem = type2.Type.GetElementType(); while (t1Elem.HasElementType) { t1Elem = t1Elem.GetElementType(); } while (t2Elem.HasElementType) { t2Elem = t2Elem.GetElementType(); } if (t1Elem == typeof(WildcardType) || t2Elem == typeof(WildcardType)) { return(true); } } } if (type1.IsPointer && type2.IsPointer) { if (type1.Type.GetElementType() == typeof(WildcardType) || type2.Type.GetElementType() == typeof(WildcardType)) { return(true); } } if (type1.IsReference && type2.IsReference) { if (type1.Type.GetElementType() == typeof(WildcardType) || type2.Type.GetElementType() == typeof(WildcardType)) { return(true); } } // any pointer type matches, well, any pointer if (type1.Type == typeof(AnyPointerType) && type2.IsPointer) { return(true); } if (type2.Type == typeof(AnyPointerType) && type1.IsPointer) { return(true); } // likewise for any by ref if (type1.Type == typeof(AnyByRefType) && type2.IsReference) { return(true); } if (type2.Type == typeof(AnyByRefType) && type1.IsReference) { return(true); } // Native int can be convereted to any pointer type if (type1.IsPointer && type2 == TypeOnStack.Get <NativeIntType>()) { return(true); } if (type2.IsPointer && type1 == TypeOnStack.Get <NativeIntType>()) { return(true); } if ((type1.IsPointer || type1.IsReference) && !(type2.IsPointer || type2.IsReference)) { return(false); } if ((type2.IsPointer || type2.IsReference) && !(type1.IsPointer || type1.IsReference)) { return(false); } if (type1.IsPointer || type1.IsReference) { return(type1.Type.GetElementType() == type2.Type.GetElementType()); } var t1 = type1.Type; var t2 = type2.Type; // The null type can be assigned to any reference type if (t1 == typeof(NullType) && !TypeHelpers.IsValueType(t2)) { return(true); } if (t2 == typeof(NullType) && !TypeHelpers.IsValueType(t1)) { return(true); } t1 = Alias(t1); t2 = Alias(t2); return(ReallyIsAssignableFrom(t1, t2)); }
private static bool ReallyIsAssignableFrom(Type t1, Type t2) { if (t1 == t2) { return(true); } if (t1 == typeof(OnlyObjectType)) { if (t2 == typeof(object)) { return(true); } return(false); } // quick and dirty base case if (t1 == typeof(object) && !TypeHelpers.IsValueType(t2)) { return(true); } // you have to box in this case if (t1 == typeof(object) && TypeHelpers.IsValueType(t2)) { return(false); } var t1Bases = GetBases(t1); var t2Bases = GetBases(t2); if (t2Bases.Any(t2b => TypeOnStack.Get(t1).IsAssignableFrom(TypeOnStack.Get(t2b)))) { return(true); } if (TypeHelpers.IsInterface(t1)) { var t2Interfaces = (LinqArray <Type>)t2.GetInterfaces(); return(t2Interfaces.Any(t2i => TypeOnStack.Get(t1).IsAssignableFrom(TypeOnStack.Get(t2i)))); } if (TypeHelpers.IsGenericType(t1) && TypeHelpers.IsGenericType(t2)) { var t1Def = t1.GetGenericTypeDefinition(); var t2Def = t2.GetGenericTypeDefinition(); if (t1Def != t2Def) { return(false); } var t1Args = t1.GetGenericArguments(); var t2Args = t2.GetGenericArguments(); for (var i = 0; i < t1Args.Length; i++) { if (!TypeOnStack.Get(t1Args[i]).IsAssignableFrom(TypeOnStack.Get(t2Args[i]))) { return(false); } } return(true); } try { return(t1.IsAssignableFrom(t2)); } catch (NotSupportedException) { // Builders, some generic types, and so on don't implement this; just assume it's *no good* for now return(false); } }