I would like to count how many times function 'ExecuteAction' appear in class method.
public class A : B
{
public void X()
{
ExecuteAction(....);
ExecuteAction(....);
}
}
And the score is 2 becouse ExecuteAction appear 2x. I need it becouse I build testing framework and would like allow for external test operator to know where current step execution is and where it will end. Is it possible to do or should I change my approach?
Thank you.
Below is the approach that demonstrates how to read method body via reflection and count all the calls of the specific method:
class Foo {
public void SomeMethod() {
ExecuteAction();
ExecuteAction();
}
public void ExecuteAction() {
//
}
}
// --- Read the IL ---
var mInfo = typeof(Foo).GetMethod("SomeMethod");
var token = typeof(Foo).GetMethod("ExecuteAction").MetadataToken;
var methodBody = mInfo.GetMethodBody();
var rawIL = methodBody.GetILAsByteArray();
int counter = 0;
var reader = new ILReader(rawIL);
while(reader.Read(mInfo)) {
if(reader.OpCode == OpCodes.Call && object.Equals(reader.MetadataToken, token)) {
System.Console.WriteLine("Method \"{0}\" call detected", reader.Operand);
counter++;
}
}
System.Console.WriteLine("Total: {0}", counter);
The ILReader
class is implemented as follows(minimal implementation for this specific task) :
class ILReader {
readonly byte[] msil;
int ptr;
public ILReader(byte[] msil) {
this.msil = msil;
}
public OpCode OpCode { get; private set; }
public int MetadataToken { get; private set; }
public object Operand { get; private set; }
public bool Read(MethodInfo methodInfo) {
if(ptr < msil.Length) {
OpCode = ReadOpCode();
Operand = ReadOperand(OpCode, methodInfo);
return true;
}
return false;
}
OpCode ReadOpCode() {
byte instruction = ReadByte();
if(instruction != 254)
return singleByteOpCode[instruction];
else
return doubleByteOpCode[ReadByte()];
}
object ReadOperand(OpCode code, MethodInfo methodInfo) {
MetadataToken = 0;
switch(code.OperandType) {
case OperandType.InlineMethod:
MetadataToken = ReadInt();
System.Type[] methodArgs = null;
if(methodInfo.GetType() != typeof(ConstructorInfo))
methodArgs = methodInfo.GetGenericArguments();
System.Type[] typeArgs = null;
if(methodInfo.DeclaringType != null)
typeArgs = methodInfo.DeclaringType.GetGenericArguments();
return methodInfo.Module.ResolveMember(MetadataToken, typeArgs, methodArgs);
}
return null;
}
byte ReadByte() {
return msil[ptr++];
}
int ReadInt() {
byte b1 = ReadByte();
byte b2 = ReadByte();
byte b3 = ReadByte();
byte b4 = ReadByte();
return (int)b1 | (((int)b2) << 8) | (((int)b3) << 16) | (((int)b4) << 24);
}
#region static
static ILReader() {
CreateOpCodes();
}
static OpCode[] singleByteOpCode;
static OpCode[] doubleByteOpCode;
static void CreateOpCodes() {
singleByteOpCode = new OpCode[225];
doubleByteOpCode = new OpCode[31];
FieldInfo[] fields = GetOpCodeFields();
for(int i = 0; i < fields.Length; i++) {
OpCode code = (OpCode)fields[i].GetValue(null);
if(code.OpCodeType == OpCodeType.Nternal)
continue;
if(code.Size == 1)
singleByteOpCode[code.Value] = code;
else
doubleByteOpCode[code.Value & 0xff] = code;
}
}
static FieldInfo[] GetOpCodeFields() {
return typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static);
}
#endregion static
}
Why not write a script that counts the number of times your function appears in your source code? Something along the lines of:
static void Main(string[] args)
{
int count = 0;
using (StreamReader sr = new StreamReader(System.IO.File.OpenRead(@"<filepath>/Program.cs")))
{
while (sr.Peek()>0)
{
string line = sr.ReadLine();
if (line.Contains("Function(")
&& !(line.Contains("class") || line.Contains("static") || line.Contains("public")))
{
count++;
}
}
}
Console.WriteLine(count);
Console.Read();
}