使用C#反射来查找声明函数的接口

时间:2018-04-30 18:15:00

标签: c# reflection .net-core

我正在寻找一种简单的方法来获取方法的反射信息,从类开始,一直返回到声明接口。这是简化的代码:

public interface Ix
{
    void Function();
}
public class X : Ix
{
    public void Function() {}
}

public class Y : X
{
}

类X的方法信息没有关于在Ix接口中声明的函数的信息。这是电话:

var info = typeof(X).GetMethod("Function");
var baseInfo = info.GetBaseDefinition()

它返回以下数据:

info.DeclaringType --> MyNamespace.X
info.ReflectedType --> MyNamespace.X
baseInfo.DeclaringType --> MyNamespace.X
baseInfo.ReflectedType --> MyNamespace.X

Y类返回相同的信息。

如何判断这个函数是在接口Ix中声明的,而不是通过所有已实现的接口和类X或Y的基类?我可能会遗漏一些简单的东西,但我无法弄清楚是什么。这可能是个错误吗?

这是.Net Core SDK版本2.1.104和Visual Studio 2017

2 个答案:

答案 0 :(得分:1)

您似乎想要反向查找可从GetInterfaceMap获取的信息。建立这个非常简单,

public static Dictionary<MethodInfo, List<(Type, MethodInfo)>> GetReverseInterfaceMap(Type t)
{
    var reverseMap = new Dictionary<MethodInfo, List<(Type, MethodInfo)>>();
    var maps = t.GetInterfaces().ToDictionary(i => i, i => t.GetInterfaceMap(i));
    foreach (var m in t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
    {
        var list = new List<(Type, MethodInfo)>();
        foreach (var (i, map) in maps)
        {
            for (int index = 0; index < map.TargetMethods.Length; index++)
            {
                var targetMethod = map.TargetMethods[index];
                if (targetMethod == m)
                {
                    list.Add((map.InterfaceType, map.InterfaceMethods[index]));
                    break;
                }
            }
        }

        reverseMap[m] = list;
    }

    return reverseMap;
}

关于界面如何工作,有几点需要注意,因为图片并不像Derived那样简单 - &gt;基地 - &gt;接口。有一个映射描述了每个接口方法调用的具体方法。此信息随时可用,因为运行时需要它来实现接口调度。然而反过来并不那么简单。一个具体方法可能是多个接口的映射。接口方法也可以是remapped by derived classes。这一切都需要考虑在内。

答案 1 :(得分:1)

这是一个扩展方法,用于检索特定Type在声明MethodInfo时实现的接口的Type

首先,获取Type的所有接口映射的辅助方法:

public static IEnumerable<InterfaceMapping> GetAllInterfaceMaps(this Type aType) =>
    aType.GetTypeInfo()
         .ImplementedInterfaces
         .Select(ii => aType.GetInterfaceMap(ii));

然后,使用帮助程序获取单个方法的接口的扩展方法:

public static Type[] GetInterfacesForMethod(this MethodInfo mi) =>
    mi.ReflectedType
      .GetAllInterfaceMaps()
      .Where(im => im.TargetMethods.Any(tm => tm == mi))
      .Select(im => im.InterfaceType)
      .ToArray();

如果你想要类的所有方法的接口,你可以改为使用它:

public static ILookup<MethodInfo, Type> GetMethodsForInterfaces(this Type aType) =>
    aType.GetAllInterfaceMaps()
         .SelectMany(im => im.TargetMethods.Select(tm => new { im.TargetType, im.InterfaceType, tm }))
         .ToLookup(imtm => imtm.tm, imtm => imtm.InterfaceType);

要获取与方法对应的接口声明,可以使用:

public static IEnumerable<MethodInfo> GetInterfaceDeclarationsForMethod(this MethodInfo mi) =>
    mi.ReflectedType
      .GetAllInterfaceMaps()
      .SelectMany(map => Enumerable.Range(0, map.TargetMethods.Length)
                                   .Where(n => map.TargetMethods[n] == mi)
                                   .Select(n => map.InterfaceMethods[n]));
相关问题