internal static Assignability IsAssignableTo()

in src/Microsoft.VisualStudio.Composition/ReflectionHelpers.cs [79:136]


        internal static Assignability IsAssignableTo(ImportDefinitionBinding import, ExportDefinitionBinding export)
        {
            Requires.NotNull(import, nameof(import));
            Requires.NotNull(export, nameof(export));

            var receivingTypeRef = import.ImportingSiteElementTypeRef;
            var exportingTypeRef = export.ExportedValueTypeRef;
            if (exportingTypeRef.IsGenericTypeDefinition && receivingTypeRef.IsGenericType)
            {
                exportingTypeRef = exportingTypeRef.MakeGenericTypeRef(receivingTypeRef.GenericTypeArguments);
            }

            // Quick assignability check to attempt to exit early if assignable, otherwise use the slower methods
            if (receivingTypeRef.IsAssignableFrom(exportingTypeRef))
            {
                return Assignability.Definitely;
            }
            else if (typeof(Delegate).GetTypeInfo().IsAssignableFrom(exportingTypeRef.ResolvedType) && typeof(Delegate).GetTypeInfo().IsAssignableFrom(receivingTypeRef.ResolvedType))
            {
                // Delegates of varying types may be assigned to each other.
                // For example Action<object, EventArgs> can be assigned to EventHandler.
                // The simplest way to test for it is to ask the CLR to do it.
                // http://stackoverflow.com/questions/23075298/how-to-detect-compatibility-between-delegate-types/23088194#23088194
                try
                {
                    Assumes.NotNull(export.ExportingMember);
                    ((MethodInfo)export.ExportingMember).CreateDelegate(receivingTypeRef.ResolvedType, null);
                    return Assignability.Definitely;
                }
                catch (ArgumentException)
                {
                    return Assignability.DefinitelyNot;
                }
                catch (TargetParameterCountException)
                {
                    return Assignability.DefinitelyNot;
                }
            }
            else
            {
                bool valueTypeKnownExactly =
                    export.ExportingMemberRef == null || // When [Export] appears on the type itself, we instantiate that exact type.
                    exportingTypeRef.ResolvedType.GetTypeInfo().IsSealed;
                if (valueTypeKnownExactly)
                {
                    // There is no way that an exported value can implement the required types to make it assignable.
                    return Assignability.DefinitelyNot;
                }

                if (receivingTypeRef.ResolvedType.GetTypeInfo().IsInterface || exportingTypeRef.ResolvedType.GetTypeInfo().IsAssignableFrom(receivingTypeRef.ResolvedType))
                {
                    // The actual exported value at runtime *may* be a derived type that *is* assignable to the import site.
                    return Assignability.Maybe;
                }

                return Assignability.DefinitelyNot;
            }
        }