C#Reflection - 我可以检查一个方法是否调用另一个方法

时间:2010-01-25 14:19:20

标签: c# reflection

我正在寻找一种方法来确保方法'A'调用方法'B'。粗略地说,这笔交易是......

class one
{
    internal static void MethodA()
    {
        //Do Something here.  SHOULD be calling B.
    }

    void MethodB()
    {
         //MUST be called by MethodA.
    }
}

class two
{
    internal void MethodA()
    {
        //Test that MethodA calls MethodB
    }
}

我应该指出,我坚持使用.Net 2.0,所以ExpressionTrees是不行的。我甚至不确定他们会帮忙,但这是我最初的想法。

编辑:这是一个内部工具可视化源的圈复杂度,所以我不关心破坏封装。此外,..这可能只需要使用System.Reflection来完成。

6 个答案:

答案 0 :(得分:4)

在许多情况下这是可行的,但是你需要打字。您要做的第一件事是使用ILReader类 - 有one here(和the one that Florian Doyon posted)的大纲。然后你想把它包装在这样的类中:

public class MethodCalls : IEnumerable<MethodInfo>
{
    MethodBase _method;

    public MethodCalls(MethodBase method)
    {
        _method = method;
    }

    public IEnumerator<MethodInfo> GetEnumerator()
    {
        // see here: http://blogs.msdn.com/haibo_luo/archive/2005/10/04/476242.aspx
        ILReader reader = new ILReader(_method);

        foreach (ILInstruction instruction in reader) {
            CallInstruction call = instruction as CallInstruction;
            CallVirtInstruction callvirt = instruction as CallVirstInstruction;
            if (call != null)
            {
                yield return ToMethodInfo(call);
            }
            else if (callvirt != null)
            {
                yield return ToMethodInfo(callvirt);
            }
        }
    }
}

MethodInfo ToMethodInfo(CallInstruction instr) { /* ... */ }

MethodInfo ToMethodInfo(CallVirtInstruction instr) { /* ... */ }

这两种ToMethodInfo都没有定义,因为CallInstruction也没有定义。尽管如此,这个大纲有望将您的问题转化为:

public static bool Calls(MethodBase caller, MethodInfo callee)
{
    return new MethodCalls(caller).Contains(callee);
}

答案 1 :(得分:2)

您可以使用Mono Cecil反映MethodA的方法正文,并查找调用call/callvirt的{​​{1}}条指示。

答案 2 :(得分:2)

IL阅读器有一个codeproject代码段,但您可能需要修补它以获取泛型支持。

http://www.codeproject.com/KB/cs/sdilreader.aspx

玩得开心!

答案 3 :(得分:1)

可能不是您正在寻找的,但您可以使用模拟框架编写单元测试。该模拟框架(例如Moq)可以验证在执行某些代码时是否在模拟中调用了一个方法。

答案 4 :(得分:1)

老实说,我认为你对课堂内部细节的实施过于痴心。

至于答案,我提供了一个对应点,考虑:

void MethodB() {
    var methodA = BuildDelegate("Method" + "A");
    methodA();
}

答案 5 :(得分:1)

你不能用手滚动模拟对象吗?这取决于你是否可以使MethodB可见和虚拟。

class one
{
    internal static void MethodA()
    {
        //Do Something here.  SHOULD be calling B.
    }

    internal virtual void MethodB()
    {
         //MUST be called by MethodA.
    }
}

class three : one
{
    public bool wasCalled;
    override void MethodB()
    {
         wasCalled=true;
    }
}


class two
{
    internal void MethodA()
    {
        three.ClassA();
        if (three.wasCalled)
        {
        }
    }
}