如何查找声明方法的接口

时间:2011-09-30 10:47:53

标签: .net reflection unity-container enterprise-library system.reflection

我正在使用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;

3 个答案:

答案 0 :(得分:0)

我能提出的唯一解决办法(尽管你的解决方案不是那么尴尬)。

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

答案 1 :(得分: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;

答案 2 :(得分:0)

我认为你坚持枚举接口;我还没有看到访问特定界面的方法。

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

我发现的唯一解决方案是剥离主要信息。 E.g。

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。但我不确定这对所有情况都是足够的。