Вам нужно получить MethodInfo. Вызовите GetMethodBody(), чтобы получить структуру тела метода, а затем вызовите GetILasByteArray для этого. Преобразование этого массива байтов в поток понятного IL.
Грубо говоря
public static List<Instruction> ReadIL(MethodInfo method)
{
MethodBody body = method.GetMethodBody();
if (body == null)
return null;
var instructions = new List<Instruction>();
int offset = 0;
byte[] il = body.GetILAsByteArray();
while (offset < il.Length)
{
int startOffset = offset;
byte opCodeByte = il[offset];
short opCodeValue = opCodeByte;
// If it's an extended opcode then grab the second byte. The 0xFE
// prefix codes aren't marked as prefix operators though.
if (OpCodeList[opCodeValue].OpCodeType == OpCodeType.Prefix
|| opCodeValue == 0xFE)
{
opCodeValue = (short) ((opCodeValue << 8) + il[offset + 1]);
offset += 1;
}
// Move to the first byte of the argument.
offset += 1;
OpCode code = OpCodeList[opCodeValue];
Int64? argument = null;
if (code.ArgumentSize() > 0)
{
Int64 arg = 0;
Debug.Assert(code.ArgumentSize() <= 8);
for (int i = 0; i < code.ArgumentSize(); ++i)
{
Int64 v = il[offset + i];
arg += v << (i*8);
}
argument = arg;
offset += code.ArgumentSize();
}
var instruction = new Instruction(startOffset, code, argument);
instructions.Add(instruction);
}
return instructions;
}
где OpCodeList строится через
OpCodeList = new Dictionary<short, OpCode>();
foreach (var opCode in typeof (OpCodes).GetFields()
.Where(f => f.FieldType == typeof (OpCode))
.Select(f => (OpCode) f.GetValue(null)))
{
OpCodeList.Add(opCode.Value, opCode);
}
Затем вы можете определить, какие инструкции являются вызовами свойств IL или поиском переменных-членов или чем-то еще, что вам нужно, и разрешить их с помощью GetType().Module.ResolveField.
(Код предостережения выше более или менее работает, но он был вырван из более крупного проекта, который я сделал, поэтому, возможно, отсутствуют мелкие детали).
Изменить: размер аргумента — это метод расширения в OpCode, который просто использует таблицу поиска, чтобы найти подходящее значение.
public static int ArgumentSize(this OpCode opCode)
{
Dictionary<OperandType, int> operandSizes
= new Dictionary<OperandType, int>()
{
{OperandType.InlineBrTarget, 4},
{OperandType.InlineField, 4},
{OperandType.InlineI, 4},
// etc., etc.
};
return operandSizes[opCode.OperandType];
}
Вы найдете размеры в ECMA 335, которые вы также необходимо просмотреть коды операций, чтобы определить, какие коды операций следует искать, чтобы найти нужные вызовы.
person
Ian G
schedule
17.09.2009