EightyOne Unite
EightyOne Unite

Reputation: 11795

C# Reflection - Can I check if one method makes a call to another

I'm looking for a way to ensure that method 'A' calls method 'B'. So roughly, the deal is..

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
    }
}

I should point out that i'm stuck on .Net 2.0 for this one so ExpressionTrees are a no go. I'm not even sure they'd help but that was my initial thought.

EDIT: This is for an internal tool to visualize cyclomatic complexity of the source so I'm not concerned with breaking encapsulation here. Also,..it's likely this is going to have to be done just using System.Reflection.

Upvotes: 4

Views: 2901

Answers (6)

plinth
plinth

Reputation: 49179

This is doable in many cases, but is going to take some typing on your part. The first thing you want to do is use an ILReader class - there's an outline of one here (and the one that Florian Doyon posted). Then you want to wrap that in a class like this:

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

Neither of the two flavors of ToMethodInfo are defined because CallInstruction is not defined either. Nonetheless, this outline will hopefully turn your problem into:

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

Upvotes: 5

Florian Doyon
Florian Doyon

Reputation: 4186

There is a codeproject snippet for an IL reader, you might have to patch it for generics support though.

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

Have fun!

Upvotes: 2

Sam Holder
Sam Holder

Reputation: 32936

can't you hand roll a mock object? It depends on if you can make MethodB visible and virtual.

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

Upvotes: 1

Pasi Savolainen
Pasi Savolainen

Reputation: 2500

To be honest, I think you're being too nosy about implementation of class' internal details.

As for the answer, I provide a counterpoint, consider:

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

Upvotes: 1

Pent Ploompuu
Pent Ploompuu

Reputation: 5414

You could use Mono Cecil to reflect on the method body of MethodA and look for call/callvirt instructions which call MethodB.

Upvotes: 2

Matthew Groves
Matthew Groves

Reputation: 26096

Maybe not exactly what you're looking for, but you could write unit tests using a mocking framework. That mocking framework (like Moq, for instance), can verify that a method has been called in the mock when exercising some code.

Upvotes: 1

Related Questions