3

如何确定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();
    }
}
4

2 回答 2

6
public class MyClass : ITest, IDecoy
{
    void ITest.DoSomething()
    {
        //called with ITest 
    }
    void IDecoy.DoSomething()
    {
        //called with IDecoy 
    }
}
于 2013-08-13T07:51:45.093 回答
2

这个问题很有趣,所以我开始看看是否有可能找到一种方法来识别使用了哪个接口,而无需已经建议的解决方案。

我使用的解决方案本质上是找到在调用者的 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
  • 查找方法调用的 IL 偏移量DoSomething并为其提取元数据标记
  • 将调用的元数据令牌DoSomething与接口中的每个令牌进行比较

我想补充一点,我不推荐或认可此代码 - 更多的是证明从学术角度实现您的目标是可能的。

于 2013-08-13T10:24:29.063 回答