Method import using Mono.Cecil

2020-04-14 03:41发布

问题:

Help me please with method import. I want to weave assembly and inject method call reference from base class defined in the other assembly (in fact it's the assembly where weaving code is defined).

private void InsertCallSetReference()
{
    //Get the load instruction to replace
    var ilProcessor = Property.SetMethod.Body.GetILProcessor();
    var argumentLoadInstructions = ilProcessor.Body.Instructions.ToList();

    MethodReference methodReference = ImportMethod("SetReference");

    foreach (var instruction in argumentLoadInstructions)
    {
        if (instruction.OpCode == OpCodes.Stfld)
        {
            ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Call, methodReference));
            ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Ldarg_1));
            ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Ldstr, DBFieldName));
            ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Ldarg_0));
            ilProcessor.Remove(instruction);
            break;
        }
    }
}

Method import code works just fine and returns method reference

private MethodReference ImportMethod(string name)
{
     var type = MongoConnectModule.Import(typeof(BaseDataObject));
     return MongoConnectModule.Import(type.Resolve().Methods.First(m => m.Name == name));
}

But after AssemblyDefinition Write call it throws me an error:

C:\dev\MongoConnect\WeavingTaskTest\Weaving\CodeWeaving.targets(32,5): error MSB4018: System.ArgumentException: Member 'System.Void MongoConnect.BaseDataObject::SetProperty(System.String,System.Object)' is declared in another module and needs to be imported

_assemblyDefinition.Write(_assemblyPath, new WriterParameters() { WriteSymbols = true, SymbolWriterProvider = debugWriterProvider });

Any idea how I could do that?

回答1:

I've found the solution. The reason was really funny.

Module.Import() method must be called from current module we want to modify, not the module where method is defined. It is not clear from original docs.

For example, we want to add some method defined in the Referenced.dll assembly to our Main.dll assembly. Then we have to find main module of our Main.dll assembly and then call MainModule.Import(methodFromReferencedAssembly);