Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reflect on C# explicit interface implementation from the call stack?

Is it possible to reflect on an explicit interface implementation from the call stack? I want to use this info to look up an attribute on the interface itself.

Given this code:

interface IFoo
{
    void Test();    
}

class Foo : IFoo
{
    void IFoo.Test() { Program.Trace(); }
}

class Program
{
    static void Main(string[] args)
    {
        IFoo f = new Foo();
        f.Test();
    }

    public static void Trace()
    {
        var method = new StackTrace(1, false).GetFrame(0).GetMethod();
        // method.???
    }
}

Specifically, in Trace(), I would like to be able to get to typeof(IFoo) from method.

In the watch window, if I look at method.ToString() it gives me Void InterfaceReflection.IFoo.Test() (InterfaceReflection is the name of my assembly).

How can I get to typeof(IFoo) from there? Must I use a name-based type lookup from the assembly itself, or is there a Type IFoo hidden somewhere in the MethodBase?

UPDATE:

Here's the final solution, thanks to Kyte

public static void Trace()
{
    var method = new StackTrace(1, false).GetFrame(0).GetMethod();
    var parts = method.Name.Split('.');
    var iname = parts[parts.Length - 2];
    var itype = method.DeclaringType.GetInterface(iname);
}

itype will have the interface type for the implementing method. This will only work with explicit interface implementations, but that's exactly what I need. Now I can use itype to query attributes attached to the actual interface type.

Thanks to everyone for their help.

like image 305
scobi Avatar asked Oct 01 '10 16:10

scobi


2 Answers

Testing around with VS2010, I found DeclaringType, which gets the object type that contains the method, from where you can get the interfaces as Type objects.

    public static void Trace() {
        var stack = new StackTrace(1, true);
        var frame = stack.GetFrame(0);
        var method = frame.GetMethod();

        var type = method.DeclaringType;

        Console.WriteLine(type);
        foreach (var i in type.GetInterfaces()) {
            Console.WriteLine(i);
        }
    }

Returns:

TestConsole.Foo
TestConsole.IFoo

(I called the project TestConsole)

like image 193
Kyte Avatar answered Sep 24 '22 18:09

Kyte


method will be a System.Reflection.RuntimeMethodInfo, which is a class derived from System.Reflect.MethodBase. You could e.g. call Invoke() on it (though if you did so at the point where you obtained it, then this is going to result in an infinite recursion that eventually dies by overflowing the stack).

Calling ToString() on it returns a fully qualified name. Did you call the project InterfaceReflection?

Not sure what more you want than that.

Edit: Okay, now I do. To find the declaring type look at the DeclaringType property, this will return the class on which the method was declared (which could be the class it was called on, or a base class):

So far so easy, this returns a Type object for Foo.

Now for the tricky bit, because you care about the interface it was declared on. However, there could be more than one interface that defined a method with precisely the same signature, which means the simple question "if this came from an interface, what was that interface?" doesn't always have a single answer.

There may be a neater way to do this, but all I can think of is calling GetInterfaces() on the Type object you got from DeclaringType, and then looking for one whose name matches the method's signature.

like image 25
Jon Hanna Avatar answered Sep 21 '22 18:09

Jon Hanna