【问题标题】:How to reflect on C# explicit interface implementation from the call stack?如何从调用栈反映 C# 显式接口实现?
【发布时间】:2011-04-19 23:15:46
【问题描述】:

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

鉴于此代码:

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)?我必须使用程序集本身的基于名称的类型查找,还是 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 来查询附加到实际接口类型的属性。

感谢大家的帮助。

【问题讨论】:

    标签: c# reflection interface


    【解决方案1】:

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

    【讨论】:

    • 啊!就是这样,谢谢。我只看属性,并没有考虑看方法。我认为GetInterfaces() 是我可以使用的。我将使用method.Name,它给了我InterfaceReflection.IFoo.Test,我将拉出“IFoo”,并使用GetInterface() 查找其匹配类型。那行得通。
    • 如果 Foo 实现了超过 1 个接口,那么你仍然需要弄清楚该方法属于哪一个......另外,如果 Test 没有在接口中定义,并且是一个实际的方法富?
    • @rally25rs: 你可以运行 i.GetMethods() 并匹配 GetFrame(0).GetMethod() 的结果
    • @Scott Bilas:那么您必须执行 Type.GetType(string),这可能比查找(已加载)要慢(取决于程序集中有多少类型)元数据。当然,这并不确定,因此可能需要进行一些测量。
    • @Kyte:不是这样。 i.GetMethods() 和 GetFrame(0).GetMethod() 返回的对象不相等。 .Name 属性也不相等(GetFrame(0).GetMethod().Name = "TestConsole.IFoo.Test" vs i.GetMethods()[0].Name = "Test")。
    【解决方案2】:

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

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

    不知道你还想要什么。

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

    到目前为止很简单,这会返回 Foo 的 Type 对象。

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

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

    【讨论】:

    • 哇。脚进嘴里。我确实调用了 InterfaceReflection 项目并忘记了它。我以为这是一个内部 .NET 名称。好的,我会更新问题。我仍然无法找到正确的接口类型。
    【解决方案3】:

    我不想假设太多,但在这种情况下,看起来你可能会造成一些混乱,因为 Foo 和 Program 是相互依赖的。通常,我认为 Program 会“拥有” Foo (这将与 Program 无关),它负责设置委托,因此可能会避免反射......你设置它的方式,Foo“拥有" (实际上,我想取决于可能更准确) Program in a way(因为它是对其 Program.Trace() 的硬调用),并且 Program 在某种程度上“拥有” Foo (因为它控制实例)。

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

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

    不过,我可能误解了你的问题。

    【讨论】:

    • 你肯定误解了我的问题。 :) 这是一个人为的例子,只是为了以最简单的方式提出问题。我真的只是对(a)如何正确地进行反射和(b)这个 InterfaceReflection.exe 业务的内容感兴趣。这个问题与建筑设计无关。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2010-10-19
      • 2010-12-21
      • 1970-01-01
      • 2012-03-01
      • 2011-02-17
      • 2015-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多