2

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

Community
  • 1
  • 1
Chris Lee
  • 51
  • 1
  • 5

0 Answers0