开发者

How to find the interface where the method is declared

开发者 https://www.devze.com 2023-04-10 06:05 出处:网络
I\'m using Unity for interception. Because I have many interfaces I\'m forced to using VirtualMethodInterceptor. In my behavior I would like to react only when the method called was declared in the pa

I'm using Unity for interception. Because I have many interfaces I'm forced to using VirtualMethodInterceptor. In my behavior I would like to react only when the method called was declared in the particular type of interfaces (with special attribute). I thought that MethodBase.DeclaringType will solve my problem but it behaves different than I was hoping to. It returns implementing type.

I can agree that it makes sense as the method can be declared in multiple interfaces but there should be a way to easily get the list of them. Unfortunately I haven’t found it yet.

Small sample showing my problem

public interface ISample
{
    void Do();
}

public class Sample : ISample
{
    public void Do()
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        var m = typeof(Sample).G开发者_运维知识库etMethod("Do") as MethodBase;
        Console.WriteLine(m.DeclaringType.Name); // Prints "Sample"
    }
}

one awkward solution:

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;


The only solution I could come up with (similar to you not-so-awkward solution though).

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


Eventually I used this code:

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;


I think you are stuck with enumerating the interfaces; I haven't seen a way to access a specific interface.

Also, there is a small edge case that could happen if the interface is implemented explicitly. In that case (void ISample.Do()) the MethodBase.Name will be the fully qualified method name (e.g. MyApp.ISample.Do) and not Do.

The only solution I found was to strip off the leading information. 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;

Also, if there is another method that has the same name and signature then I'm not sure how to determine if the method was called via the interface as opposed to the public method.

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

    void ISample.Do()
    {
        // this is the interface implementation
    }
}

I guess it might be possible to look for other methods with the same name and signature and differentiate by looking at the other MethodBase properties.

I.e. public void Do() has IsHideBySig and IsPublic set to true while void ISample.Do() has IsFinal, IsVirtual, IsPrivate, IsHideBySig all set to true. But I'm not sure that is sufficient for all scenarios.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号