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