Генерировать операторы Emit из IL - PullRequest
0 голосов
/ 03 марта 2020

Я хочу добавить тело метода без прохождения операторов Emit. Аналогично:

public static void Replicate<T>(this MethodBuilder methodBuilder, Func<T> func)
{
    var body = func.Method.GetMethodBody();
    var instructions = body.GetILAsByteArray();
    methodBuilder.CreateMethodBody(instructions, instructions.Length);
}
var methodBuilder = typeBuilder.DefineMethod("GetExtensionCollection", MethodAttributes.Public, typeof(Stream), Type.EmptyTypes);
methodBuilder.Replicate(() =>
{
    var assembly = Assembly.GetExecutingAssembly();
    return assembly.GetManifestResourceStream(assembly.GetName().Name + ".Extensions.xml");
});

Когда я декомпилирую сгенерированную сборку с использованием dnSpy, код IL полностью неверен, а код C# вызывает исключение. enter image description here enter image description here

Я также попробовал следующее на основе Создайте копию метода из IL , и я изменил Mono.Reflection :

public static void Replicate<T>(this MethodBuilder methodBuilder, Func<T> func)
{
    var il = methodBuilder.GetILGenerator();
    foreach (var local in func.Method.GetMethodBody().LocalVariables)
        il.DeclareLocal(local.LocalType);
    foreach (var instrcustion in func.Method.GetInstructions())
    {
        if (instrcustion.OpCode.OperandType == OperandType.InlineBrTarget)
        {
            il.Emit(instrcustion.OpCode, Convert.ToInt32(instrcustion.Operand));
            continue;
        }
        if (instrcustion.OpCode.OperandType == OperandType.ShortInlineBrTarget)
        {
            continue;
        }
        if (instrcustion.OpCode.OperandType == OperandType.InlineString)
        {
            il.Emit(instrcustion.OpCode, instrcustion.Operand.ToString());
            continue;
        }
        if (instrcustion.OpCode.OperandType == OperandType.InlineType)
        {
            il.Emit(instrcustion.OpCode, instrcustion.Operand as Type);
            continue;
        }
        if (instrcustion.OpCode.FlowControl == FlowControl.Call)
        {
            var methodInfo = instrcustion.Operand as MethodInfo;
            if (methodInfo == func.Method)
                il.Emit(instrcustion.OpCode, methodBuilder);
            else
                il.Emit(instrcustion.OpCode, methodInfo);
            continue;
        }
        il.Emit(instrcustion.OpCode);
    }
}

Этот работает, но мне нужно:

  • Желательно, чтобы первый Replicate работал
  • Если не удастся, создайте полную версию второй Replicate
...