I have reviewed some related questions and others.
I'm trying to create an extension method for System.Type and a companion for System.Reflection.MethodBase to find all extension methods for a given type.
I have the following:
public static class MethodBaseExtensions
{
public static bool IsExtensionMethodForType(this MethodBase method, Type type)
{
if (1 > method.GetParameters().Count() || !method.IsDefined(typeof(ExtensionAttribute), false))
{
return false;
}
var extendedType = method.GetParameters().First().ParameterType;
if (!method.GetGenericArguments().Any(arg => arg.Equals(extendedType)))
{
if (extendedType.IsGenericType)
{
return extendedType.IsGenericTypeAssignableFrom(type);
}
return extendedType.IsAssignableFrom(type);
}
foreach (var constraint in extendedType.GetGenericParameterConstraints())
{
if (constraint.IsGenericType && !constraint.IsGenericTypeAssignableFrom(type))
{
return false;
}
if (!constraint.IsGenericType && !constraint.IsAssignableFrom(type))
{
return false;
}
}
return true;
}
}
which is used by:
public static class TypeExtensions
{
public static MethodInfo GetExtensionMethod(this Type type, string name)
{
return type.GetExtensionMethods().Single(m => m.Name.Equals(name, StringComparison.Ordinal));
}
public static IEnumerable<MethodInfo> GetExtensionMethods(this Type type)
{
return type.GetExtensionMethods(type.Assembly);
}
public static IEnumerable<MethodInfo> GetExtensionMethods(this Type type, Assembly assembly)
{
return type.GetExtensionMethods(new Assembly[] { assembly });
}
public static IEnumerable<MethodInfo> GetExtensionMethods(this Type type, IEnumerable<Assembly> assemblies)
{
const BindingFlags BINDING_FLAGS = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
return assemblies
.SelectMany(assembly => assembly.GetTypes().Where(t => t.IsExtensionMethodClass())
.SelectMany(t => t.GetMethods(BINDING_FLAGS))
.Where(m => m.IsExtensionMethodForType(type)));
}
public static bool IsGenericTypeAssignableFrom(this Type type, Type assignedType)
{
if (type.IsAssignableFrom(assignedType))
{
return true;
}
if (assignedType.IsGenericType &&
assignedType.GetGenericTypeDefinition().IsAssignableFrom(type))
{
return true;
}
foreach (var interfaceType in assignedType.GetInterfaces())
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition().IsAssignableFrom(type))
{
return true;
}
}
if (default(Type) == assignedType.BaseType)
{
return false;
}
return type.IsGenericTypeAssignableFrom(assignedType.BaseType);
}
public static bool IsExtensionMethodClass(this Type type)
{
return type.IsSealed && !type.IsGenericType && !type.IsNested && type.IsDefined(typeof(ExtensionAttribute), false);
}
}
The challenge is that typeof(IFoo<>).GetExtensionMethods()
will not find Test2
in
public static class IFooExtensions
{
public static void Test1(this IFoo<int> foo, int i)
{ }
public static void Test2<TFoo, T>(this TFoo foo, T t)
where TFoo : IFoo<T>
{ }
}
unless I adjust MethodBaseExtensions.IsExtensionMethodForType
to get the generic type definition of both types, which ends up making typeof(IFoo<string>).GetExtensionMethods()
also return Test1
.
When debugging I find that both IFoo<T>
and IFoo<>
become IFoo`1
but they're apparently different types of IFoo`1
.
At this point I'm kind of chasing my tail here, looking for a solution.
TIA