如何从调用堆栈反映C#显式接口实现?

时间:2010-10-01 16:45:33

标签: c# reflection interface

是否可以反映调用堆栈中的显式接口实现?我想使用此信息在界面本身上查找属性。

鉴于此代码:

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.???
    }
}

具体来说,在Trace()中,我希望能够从typeof(IFoo)转到method

在观察窗口中,如果我查看method.ToString(),它会给我Void InterfaceReflection.IFoo.Test()(InterfaceReflection是我的程序集的名称)。

如何从那里到达typeof(IFoo)?我必须从程序集本身使用基于名称的类型查找,还是Type IFoo中某处隐藏了MethodBase

更新

这是最终解决方案,感谢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将具有实现方法的接口类型。这只适用于显式接口实现,但这正是我需要的。现在我可以使用itype来查询附加到实际接口类型的属性。

感谢大家的帮助。

4 个答案:

答案 0 :(得分:3)

使用VS2010进行测试,我找到了DeclaringType,它获取包含该方法的对象类型,从中可以将接口作为Type对象。

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

返回:

TestConsole.Foo
TestConsole.IFoo

(我称之为TestConsole项目)

答案 1 :(得分:2)

method将是System.Reflection.RuntimeMethodInfo,这是一个派生自System.Reflect.MethodBase的类。你可以,例如在它上面调用Invoke()(尽管如果你在获得它的时候这样做了,那么这将导致无限递归,最终因堆栈溢出而死亡)。

在其上调用ToString()会返回一个完全限定的名称。你有没有把项目称为InterfaceReflection?

不确定你想要的更多。

编辑:好的,现在我做。要查找声明类型,请查看DeclaringType属性,这将返回声明方法的类(可以是调用它的类,或基类):

到目前为止很容易,这会为Foo返回一个Type对象。

现在对于棘手的一点,因为你关心它被声明的接口。但是,可能有多个接口定义了一个具有完全相同签名的方法,这意味着简单的问题“如果这来自一个接口,那个接口是什么?”并不总是有一个答案。

可能有一种更简洁的方法可以做到这一点,但我能想到的只是在你GetInterfaces()的{​​{1}}对象上调用Type,然后找一个名字的人匹配方法的签名。

答案 2 :(得分:0)

我不想过多假设,但在这种情况下,看起来你可能会引起一些混乱,因为Foo和Program是相互依赖的。通常情况下,我认为程序会“拥有”Foo(这将是程序的不可知),它负责设置委托,因此可以避免反思...你设置它的方式,Foo“拥有“(实际上,我认为取决于它可能更准确)程序的某种方式(因为它很难调用它的Program.Trace()),而程序”拥有“Foo的方式(因为它控制实例)。 / p>

我不知道这是否适用于您的特定场景,但看起来事件类型操作可能更有意义并且更简单地处理通信。

ETA:代码示例:

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)
        { 
            //...
        }
    }
}
但是,我可能会误解你的问题。

答案 3 :(得分:0)

我认为.NET将全名附加到MethodInfo.Name属性的前面,以便它为每个方法都有一个唯一的名称。想一想:

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

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

在这种情况下,typeof(Foo).GetMethods()会返回两个Test()方法,但它们的名称会发生​​冲突,所以我猜它们会附加接口名称以使它们唯一?

MethodInfo.DeclaringType返回包含实现的类型。因此,如果IFoo实际上是一些基类型而不是接口,并且那里有一个基本方法声明,那么.DeclaringType将返回基类的类型。

有趣的是,我似乎无法在MethodInfo中的任何地方找到实际的接口名称,所以我想你必须按名称查找它,例如:

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