0

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

3 回答 3

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;
}
于 2011-09-30T11:16:59.100 回答
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;
于 2011-10-03T09:42:27.393 回答
0

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

此外,如果显式实现接口,可能会发生一个小的边缘情况。在这种情况下 ( void ISample.Do()) MethodBase.Name 将是完全限定的方法名称(例如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。但我不确定这是否足以满足所有场景。

于 2011-10-03T16:28:09.373 回答