简体   繁体   English

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

[英]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 . 具体来说,在Trace()中,我希望能够从method转到typeof(IFoo)

In the watch window, if I look at method.ToString() it gives me Void InterfaceReflection.IFoo.Test() (InterfaceReflection is the name of my assembly). 在监视窗口中,如果我查看method.ToString()它将为我提供Void InterfaceReflection.IFoo.Test() (InterfaceReflection是我的程序集的名称)。

How can I get to typeof(IFoo) from there? 如何从那里进入typeof(IFoo) Must I use a name-based type lookup from the assembly itself, or is there a Type IFoo hidden somewhere in the MethodBase ? 我必须从程序集本身使用基于名称的类型查找,还是在MethodBase某个位置隐藏Type IFoo

UPDATE: 更新:

Here's the final solution, thanks to Kyte 这是最终的解决方案,感谢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. itype将具有实现方法的接口类型。 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. 现在,我可以使用itype来查询附加到实际接口类型的属性。

Thanks to everyone for their help. 感谢大家的帮助。

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

Returns: 返回值:

TestConsole.Foo
TestConsole.IFoo

(I called the project TestConsole) (我称这个项目为TestConsole)

method will be a System.Reflection.RuntimeMethodInfo , which is a class derived from System.Reflect.MethodBase . method将是System.Reflection.RuntimeMethodInfo ,这是从System.Reflect.MethodBase派生的类。 You could eg 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). 您可以例如在其上调用Invoke() (尽管如果在获取它的那一点上调用了Invoke() ,那么这将导致无限递归并最终由于溢出堆栈而消失)。

Calling ToString() on it returns a fully qualified name. 在其上调用ToString()将返回完全限定的名称。 Did you call the project InterfaceReflection? 您是否将项目称为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): 要查找声明类型,请查看DeclaringType属性,这将返回在其上声明了该方法的类(可以是在其上调用的类或基类):

So far so easy, this returns a Type object for Foo. 到目前为止,到目前为止,这很容易为Foo返回Type对象。

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

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

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. 不过,我可能会误解您的问题。

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. 我认为.NET将全名附加到MethodInfo.Name属性的前面,以便它对每个方法都有唯一的名称。 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? 在这种情况下, typeof(Foo).GetMethods()将返回两个Test()方法,但是它们的名称会发生​​冲突,因此我猜想它们会附加接口名称以使其唯一吗?

The MethodInfo.DeclaringType returns the type that contains the implementation. MethodInfo.DeclaringType返回包含实现的类型。 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. 因此,如果IFoo实际上是某个基本类型而不是一个接口,并且那里有一个基本方法声明,则.DeclaringType将返回该基类的类型。

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: 有趣的是,我似乎也无法在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