views:

84

answers:

4

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.

A: 

I don't want to presume too much, but in this case, it looks like you may be causing some confusion because Foo and Program are inter-dependent. Typically, I would think Program would "own" Foo (which would be agnostic of Program) in such a way that it's responsible for setting the delegate so reflection could likely be avoided...the way you have it set up, Foo "owns" (actually, I guess depends on is probably more accurate) Program in a way (because it's hardcoing a a call to its Program.Trace() ), and Program "owns" Foo in a way (because it controls the instance).

I don't know if this would work in your particular scenerio, but it looks like an event type operation might make more sense and handle the communication more simply.

ETA: Code sample:

public interface IFoo
{
    event EventHandler Testing;
    void Test();
}
public class Foo : IFoo
{
    public event EventHandler Testing;
    protected void OnTesting(EventArgs e)
    {
        if (Testing != null)
            Testing(this, e);
    }
    public void Test()
    {
        OnTesting(EventArgs.Empty);
    }
}

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        IFoo f = new Foo();
        f.Testing += new EventHandler(f_Testing);
        f.Test();
    }

    static void f_Testing(object sender, EventArgs e)
    {
        IFoo foo = sender as IFoo;
        if (foo != null)
        { 
            //...
        }
    }
}

I might be misunderstanding your question, though.

Steven
You're definitely misunderstanding my question. :) This is a contrived example solely for the purpose of asking the question in the simplest possible way. I really am just interested in (a) how to get the reflection right and (b) what this InterfaceReflection.exe business is about. This question is not about architectural design.
Scott Bilas
+2  A: 

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.

Jon Hanna
Wow. Foot in mouth. I did indeed call the project InterfaceReflection and forgot about it. I was thinking it was an internal .NET name. Ok, I'll update the question. I still have the problem of finding the correct interface type.
Scott Bilas
@Scott Bilas okily, have updated my answer accordingly.
Jon Hanna
+1  A: 

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)

Kyte
Ah! That's it, thank you. I was only looking at properties, and didn't think to look at methods. I think `GetInterfaces()` is what I can use. I'll use `method.Name` which gives me `InterfaceReflection.IFoo.Test`, I'll pull out the "IFoo", and use `GetInterface()` to find its matching type. That works.
Scott Bilas
If Foo implemented more than 1 interface, then you would still have to figure out which one the method belongs to... Plus what if Test was not defined in the Interface, and was an actual method of Foo?
rally25rs
@rally25rs: You can run i.GetMethods() and match against the result of GetFrame(0).GetMethod()
Kyte
@Scott Bilas: Then you'd have to do Type.GetType(string), which might be slower (depending on how many types there are in the assembly) than looking up the (already loaded) metadata. Of course, that's not certain, so some measuring might be in order.
Kyte
@Kyte: Not really. The object returned by `i.GetMethods()` and `GetFrame(0).GetMethod()` are not equal. The `.Name` property is also not equal (GetFrame(0).GetMethod().Name = "TestConsole.IFoo.Test" vs i.GetMethods()[0].Name = "Test").
rally25rs
See my updated Trace in the the question. I believe this is fast and accurate. No problems with multiple interfaces or Type.GetType perf issues.
Scott Bilas
A: 

I think .NET appends the full name to the front of the MethodInfo.Name property so that it has a unique name for each method. Think of:

interface IFoo
{
    void Test();
}
interface IFoo2
{
    void Test();
}

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

In this case, typeof(Foo).GetMethods() would return both Test() methods but their names would conflict, so I guess they appended the interface name to make them unique?

The MethodInfo.DeclaringType returns the type that contains the implementation. So if IFoo were actually some base type instead of an interface, and there was a base method declaration there, then .DeclaringType would return the type of the base class.

Interestingly, I can't seem to find the actual interface name anywhere in the MethodInfo either, so I guess you would have to look it up by name, something like:

    public static void Trace()
    {
        var method = new System.Diagnostics.StackTrace(1, false).GetFrame(0).GetMethod();
        var fromType = method.DeclaringType;
        if (method.Name.Contains("."))
        {
            var iname = method.Name.Substring(0, method.Name.LastIndexOf('.'));
            fromType = Type.GetType(iname); // fromType is now IFoo.
        }
    }
rally25rs