如何找到声明方法的接口



我使用Unity进行拦截。因为我有很多接口,所以我不得不使用VirtualMethodInterceptor。在我的行为中,我希望仅当调用的方法在特定类型的接口(具有特殊属性)中声明时才做出反应。我认为MethodBase。DeclaringType将解决我的问题,但它的行为与我希望的不同。它返回实现类型。

我同意这是有意义的,因为方法可以在多个接口中声明,但应该有一种方法可以轻松地获得它们的列表。可惜我还没找到。

小样本显示我的问题

public interface ISample
{
    void Do();
}
public class Sample : ISample
{
    public void Do()
    {
    }
}
class Program
{
    static void Main(string[] args)
    {
        var m = typeof(Sample).GetMethod("Do") as MethodBase;
        Console.WriteLine(m.DeclaringType.Name); // Prints "Sample"
    }
}

一个尴尬的解决方案:

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces()
                where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0
                where i.GetMethod(input.MethodBase.Name, input.MethodBase.GetParameters().Select(p=>p.ParameterType).ToArray()) != null
                select i;

我能想到的唯一解决方案(类似于你不那么尴尬的解决方案)。

public static bool IsMethodDeclaredInInterface(MethodBase method, Type myInterface)
{
    var methodType = method.DeclaringType;
    var typeFilter = new TypeFilter((t, crit) =>
                                        {
                                            var critTypes = crit as Type[];
                                            return critTypes != null && critTypes.Any(ty => ty.FullName == t.FullName);
                                        });
    var res = methodType.FindInterfaces(typeFilter, new[] {myInterface});
    return res.Length > 0;
}

最后我使用了下面的代码:

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces()
                 let parameters = input.MethodBase.GetParameters().Select(p=>p.ParameterType).ToArray()
                 where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0
                 where i.GetMethod(input.MethodBase.Name, parameters) != null
                 select i;

我认为你被困在枚举接口;我还没有看到访问特定接口的方法。

此外,如果显式实现接口,可能会出现一个小的边缘情况。在这种情况下(void ISample.Do()) MethodBase。名称将是完全限定的方法名称(例如MyApp.ISample.Do),而不是Do

我找到的唯一解决办法是去掉引导信息。例如

string methodName = input.MethodBase.Name;
int methodIndex = methodName.LastIndexOf('.');
if (methodIndex != -1)
{
    methodName = methodName.Substring(methodIndex + 1, 
        methodName.Length - methodIndex - 1);
}
var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces()
                 let parameters = input.MethodBase.GetParameters().
                     Select(p => p.ParameterType).ToArray()
                 where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0
                 where i.GetMethod(methodName, parameters) != null
                 select i;

另外,如果有另一个方法具有相同的名称和签名,那么我不确定如何确定该方法是否通过接口而不是公共方法调用。

public class Sample : ISample
{
    public void Do()
    {
        // this is a public method
    }
    void ISample.Do()
    {
        // this is the interface implementation
    }
}

我想这可能是有可能寻找其他方法与相同的名称和签名,并通过查看其他MethodBase属性区分。

public void Do()有IsHideBySig和IsPublic设置为true,而void ISample.Do()有IsFinal, IsVirtual, IsPrivate, IsHideBySig都设置为true。但我不确定这对所有情况都足够。

相关内容

  • 没有找到相关文章