// Internally callable version of the export method above. Has two additional parameters: // fBoxedSource : assume the source type is boxed so that value types and enums are // compatible with Object, ValueType and Enum (if applicable) // fAllowSizeEquivalence : allow identically sized integral types and enums to be considered // equivalent (currently used only for array element types) static internal unsafe bool AreTypesAssignableInternal(EEType *pSourceType, EEType *pTargetType, bool fBoxedSource, bool fAllowSizeEquivalence) { // // Are the types identical? // if (AreTypesEquivalentInternal(pSourceType, pTargetType)) { return(true); } // // Handle cast to interface cases. // if (pTargetType->IsInterface) { // Value types can only be cast to interfaces if they're boxed. if (!fBoxedSource && pSourceType->IsValueType) { return(false); } if (ImplementsInterface(pSourceType, pTargetType)) { return(true); } // Are the types compatible due to generic variance? if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance) { return(TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType)); } return(false); } if (pSourceType->IsInterface) { // The only non-interface type an interface can be cast to is Object. return(WellKnownEETypes.IsSystemObject(pTargetType)); } // // Handle cast to array or pointer cases. // if (pTargetType->IsParameterizedType) { if (pSourceType->IsParameterizedType && (pTargetType->ParameterizedTypeShape == pSourceType->ParameterizedTypeShape)) { // Source type is also a parameterized type. Are the parameter types compatible? Note that using // AreTypesAssignableInternal here handles array covariance as well as IFoo[] -> Foo[] // etc. Pass false for fBoxedSource since int[] is not assignable to object[]. if (pSourceType->RelatedParameterType->IsPointerTypeDefinition) { // If the parameter types are pointers, then only exact matches are correct. // As we've already called AreTypesEquivalent at the start of this function, // return false as the exact match case has already been handled. // int** is not compatible with uint**, nor is int*[] oompatible with uint*[]. return(false); } else { return(AreTypesAssignableInternal(pSourceType->RelatedParameterType, pTargetType->RelatedParameterType, false, true)); } } // Can't cast a non-parameter type to a parameter type or a parameter type of different shape to a parameter type return(false); } if (pSourceType->IsArray) { // Target type is not an array. But we can still cast arrays to Object or System.Array. return(WellKnownEETypes.IsSystemObject(pTargetType) || WellKnownEETypes.IsSystemArray(pTargetType)); } else if (pSourceType->IsParameterizedType) { return(false); } // // Handle cast to other (non-interface, non-array) cases. // if (pSourceType->IsValueType) { // Certain value types of the same size are treated as equivalent when the comparison is // between array element types (indicated by fAllowSizeEquivalence). These are integer types // of the same size (e.g. int and uint) and the base type of enums vs all integer types of the // same size. if (fAllowSizeEquivalence && pTargetType->IsValueType) { if (ArePrimitveTypesEquivalentSize(pSourceType, pTargetType)) { return(true); } // Non-identical value types aren't equivalent in any other case (since value types are // sealed). return(false); } // If the source type is a value type but it's not boxed then we've run out of options: the types // are not identical, the target type isn't an interface and we're not allowed to check whether // the target type is a parent of this one since value types are sealed and thus the only matches // would be against Object, ValueType or Enum, all of which are reference types and not compatible // with non-boxed value types. if (!fBoxedSource) { return(false); } } // Sub case of casting between two instantiations of the same delegate type where one or more of // the type parameters have variance. Only interfaces and delegate types can have variance over // their type parameters and we know that neither type is an interface due to checks above. if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance) { // We've dealt with the identical case at the start of this method. And the regular path below // will handle casting to Object, Delegate and MulticastDelegate. Since we don't support // deriving from user delegate classes any further all we have to check here is that the // uninstantiated generic delegate definitions are the same and the type parameters are // compatible. return(TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType)); } // Is the source type derived from the target type? if (IsDerived(pSourceType, pTargetType)) { return(true); } return(false); }
static public /*internal*/ unsafe object IsInstanceOfClass(object obj, void *pvTargetType) { if (obj == null) { return(null); } EEType *pTargetType = (EEType *)pvTargetType; EEType *pObjType = obj.EEType; Debug.Assert(!pTargetType->IsParameterizedType, "IsInstanceOfClass called with parameterized EEType"); Debug.Assert(!pTargetType->IsInterface, "IsInstanceOfClass called with interface EEType"); // if the EETypes pointers match, we're done if (pObjType == pTargetType) { return(obj); } // Quick check if both types are good for simple casting: canonical, no related type via IAT, no generic variance if (System.Runtime.EEType.BothSimpleCasting(pObjType, pTargetType)) { // walk the type hierarchy looking for a match do { pObjType = pObjType->BaseType; if (pObjType == null) { return(null); } if (pObjType == pTargetType) { return(obj); } }while (pObjType->SimpleCasting()); } if (pTargetType->IsCloned) { pTargetType = pTargetType->CanonicalEEType; } if (pObjType->IsCloned) { pObjType = pObjType->CanonicalEEType; } // if the EETypes pointers match, we're done if (pObjType == pTargetType) { return(obj); } if (pTargetType->HasGenericVariance && pObjType->HasGenericVariance) { // Only generic interfaces and delegates can have generic variance and we shouldn't see // interfaces for either input here. So if the canonical types are marked as having variance // we know we've hit the delegate case. We've dealt with the identical case just above. And // the regular path below will handle casting to Object, Delegate and MulticastDelegate. Since // we don't support deriving from user delegate classes any further all we have to check here // is that the uninstantiated generic delegate definitions are the same and the type // parameters are compatible. return(TypesAreCompatibleViaGenericVariance(pObjType, pTargetType) ? obj : null); } if (pObjType->IsArray) { // arrays can be cast to System.Object if (WellKnownEETypes.IsSystemObject(pTargetType)) { return(obj); } // arrays can be cast to System.Array if (WellKnownEETypes.IsSystemArray(pTargetType)) { return(obj); } return(null); } // walk the type hierarchy looking for a match while (true) { pObjType = pObjType->NonClonedNonArrayBaseType; if (pObjType == null) { return(null); } if (pObjType->IsCloned) { pObjType = pObjType->CanonicalEEType; } if (pObjType == pTargetType) { return(obj); } } }