我可以在接口方法中检索接口类型吗

本文关键字:检索 接口类型 方法 接口 我可以 | 更新日期: 2023-09-27 18:27:30

如何确定调用方法DoSomething()的底层接口?附加问题:我可以在MyClass构造函数中确定底层接口吗?我假设不是,因为它在实例化时是未知的,对吗?

编辑:我不是在寻找显式接口实现,而是用不同的方式来确定底层接口。

public interface ITest
{
    void DoSomething();
    //....more methods
}
public interface IDecoy
{
    void DoSomething();
    //...more methods
}
public class MyClass : ITest, IDecoy
{
    public void DoSomething()
    {
        //Question: How can I determine the underlying interface that called this method?
        //at one time it is ITest, at another IDecoy. How can I figure out which one at each time?
    }
}
public class Test
{
    public Test()
    {
        ITest myClassInstance1 = new MyClass();
        IDecoy myClassInstance2 = new MyClass();
        myClassInstance1.DoSomething();
        myClassInstance2.DoSomething();
    }
}

我可以在接口方法中检索接口类型吗

public class MyClass : ITest, IDecoy
{
    void ITest.DoSomething()
    {
        //called with ITest 
    }
    void IDecoy.DoSomething()
    {
        //called with IDecoy 
    }
}

这个问题很有趣,所以我开始研究是否有可能在没有建议的解决方案的情况下找到一种方法来识别使用了哪个接口。

我使用的解决方案本质上是在调用方的IL代码中找到被调用的方法的元数据令牌,并根据每个接口的DoSomething方法的元数据标记进行查找:

public void DoSomething()
{
    StackFrame CallerFrame;
    StackTrace CallStack;
    int CodeOffset;
    MethodBody MethodBody;
    int MethodToken;
    int TokenIDecoy;
    int TokenITest;
    // Get the metadata tokens for both interface methods
    TokenIDecoy = Type.GetType("Proto.SO18203446.IDecoy").GetMethod("DoSomething").MetadataToken;
    TokenITest = Type.GetType("Proto.SO18203446.ITest").GetMethod("DoSomething").MetadataToken;
    // Get the caller
    CallStack = new StackTrace();
    CallerFrame = CallStack.GetFrame(1);
    // Get the metadata token called by the IL
    CodeOffset = CallerFrame.GetILOffset();
    MethodBody = CallerFrame.GetMethod().GetMethodBody();
    MethodToken = BitConverter.ToInt32(MethodBody.GetILAsByteArray(), CodeOffset - 4);
    // Check to see which interface was used
    if (MethodToken == TokenIDecoy)
        Console.WriteLine("IDecoy was called");
    else if (MethodToken == TokenITest)
        Console.WriteLine("ITest was called");
    else
        Console.WriteLine("Not sure what happened here");
}

记住将GetType调用参数更改为您自己的命名空间(所以我的是Proto.SO18203446,但您的很可能是其他命名空间)。

这个过程的步骤很简单:

  • 查找每个接口DoSomething方法的元数据标记
  • 查找调用帧(对DoSomething进行调用的帧)
  • 查找对DoSomething方法的调用的IL偏移量,并为其提取元数据令牌
  • 将调用的元数据令牌与接口中每个DoSomething的令牌进行比较

我想补充一点,我并不建议或支持这一准则——它更多的是为了证明从学术角度来看,实现你的目标是可能的。