Reputation: 11795
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
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
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
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
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
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
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