当类型可能是通用的时,如何检测类型的所有扩展方法?

时间:2014-09-08 22:39:55

标签: c# generics reflection extension-methods

我已审核了some related questions和其他人。

我试图为System.Type创建一个扩展方法,并为System.Reflection.MethodBase创建一个伴随,以查找给定类型的所有扩展方法。

我有以下内容:

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

用于:

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

挑战是typeof(IFoo<>).GetExtensionMethods()

中找不到Test2
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>
    { }
} 

除非我调整MethodBaseExtensions.IsExtensionMethodForType以获取两种类型的通用类型定义,最终使typeof(IFoo<string>).GetExtensionMethods()也返回Test1

调试时,我发现IFoo<T>IFoo<>都变为IFoo`1,但他们显然是IFoo`1的不同类型。

此时我正在寻找一个解决方案。

TIA

0 个答案:

没有答案