繁体   English   中英

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

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

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

给出以下代码:

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()中,我希望能够从method转到typeof(IFoo)

在监视窗口中,如果我查看method.ToString()它将为我提供Void InterfaceReflection.IFoo.Test() (InterfaceReflection是我的程序集的名称)。

如何从那里进入typeof(IFoo) 我必须从程序集本身使用基于名称的类型查找,还是在MethodBase某个位置隐藏Type IFoo

更新:

这是最终的解决方案,感谢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来查询附加到实际接口类型的属性。

感谢大家的帮助。

在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)

method将是System.Reflection.RuntimeMethodInfo ,这是从System.Reflect.MethodBase派生的类。 您可以例如在其上调用Invoke() (尽管如果在获取它的那一点上调用了Invoke() ,那么这将导致无限递归并最终由于溢出堆栈而消失)。

在其上调用ToString()将返回完全限定的名称。 您是否将项目称为InterfaceReflection?

不知道您想要什么。

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

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

现在,请注意一点,因为您关心的是在其上声明的接口。 但是,可能有多个接口定义了具有完全相同签名的方法,这意味着一个简单的问题:“如果它来自某个接口,那么该接口是什么?” 并非总是有一个答案。

可能有一种更整洁的方法,但是我能想到的就是在从DeclaringType获得的Type对象上调用GetInterfaces() ,然后寻找名称与方法签名匹配的对象。

我不想设定太多,但是在这种情况下,由于Foo和Program是相互依赖的,因此您似乎引起了一些混乱。 通常,我会认为Program会以某种方式“拥有” Foo(这与Program无关),它负责设置委托,因此可以避免反思……您的设置方式是,Foo拥有“(实际上,我想取决于它可能更准确)以某种方式编程(因为它很难调用其Program.Trace()),而程序以某种方式“拥有” Foo(因为它控制了实例)。

我不知道这是否适用于您的特定场景,但似乎事件类型的操作可能更有意义,并且可以更轻松地处理通信。

预计到达时间:代码示例:

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)
        { 
            //...
        }
    }
}

不过,我可能会误解您的问题。

我认为.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.
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM