2015-09-19 2 views
3

Вот мой код:Почему Mono.Cecil утверждает, что импорт метода пока я уже сделал?

private void ModifyMethods() 
    { 
     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@" 
using System; 

namespace ToIL 
{ 
    public class Class1 
    { 
     public void Write() 
     { 
      Console.WriteLine(""Hello""); 
     } 
    } 
}"); 


     string assemblyName = System.IO.Path.GetRandomFileName(); 
     MetadataReference[] references = new MetadataReference[] 
     { 
      MetadataReference.CreateFromFile(typeof(object).Assembly.Location), 
      MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location) 
     }; 

     CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, syntaxTrees: new[] { syntaxTree }, references: references, 
      options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); 


     Mono.Cecil.AssemblyDefinition asm = null; 
     using (var ms = new MemoryStream()) 
     { 
      var emitResult = compilation.Emit(ms); 
      if (emitResult.Success) 
      { 
       ms.Seek(0, SeekOrigin.Begin); 
       asm = Mono.Cecil.AssemblyDefinition.ReadAssembly(ms); 
      } 
     } 


     var class1 = asm.MainModule.Assembly.MainModule.Types.FirstOrDefault(T => T.Name == "Class1"); 
     var Method1 = class1.Methods.FirstOrDefault(M => M.Name == "Write"); 
     var ils = Method1.Body.Instructions; 


     System.Reflection.MethodInfo mWriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); 
     Mono.Cecil.AssemblyDefinition asmx = Mono.Cecil.AssemblyDefinition.ReadAssembly(@"EditAsm.exe"); 
     var import = asmx.MainModule.Import(mWriteLine); 
     foreach (var type in asmx.MainModule.Types) 
     { 
      if (type.Name == "<Module>") continue; 
      foreach (var method in type.Methods) 
      { 
       var cilWorker = method.Body.GetILProcessor(); 
       foreach (var il in ils) cilWorker.Append(il); 
      } 
     } 

     asmx.Write(@"d:\test.dll"); // Import Exception 

    } 

Что делает этот код является то, что составляет Write метод внутри Class1 сборки ToIL. Затем IL (Инструкции) тела метода хранится в ils. Наконец, инструкции добавляются ко всем методам сборки EditAsm.exe.
Как предусмотрено я импортировал WriteLine, но до сих пор адресности следующего исключения при asmx.Write(@"d:\test.dll");

Member 'System.Void System.Console::WriteLine(System.String)' is declared in another module and needs to be imported

ответ

3

Это потому, что ваши инструкции IL принадлежат к другому модулю, поэтому ссылки метод в них являются недопустимыми для модуля вы добавляете их , Импорт фактически создает ссылку на внешний метод (поле и т. Д.), Но эта ссылка действительна для конкретного модуля. Все ваши операнды вызова метода IL имеют ссылки, относящиеся к модулю с именем «assemblyName» в вашем коде. Эта строка:

var import = asmx.MainModule.Import(mWriteLine); 

ничего не делает, потому что вы не используете возвращаемое значение. Как вы можете его использовать (в общем)? Пример:

cilWorker.Append(Instruction.Create(OpCodes.Call, import)); 

Вы видите, что для создания команды вызова метода требуется указание метода для этого конкретного модуля, к которому вы добавляете инструкцию. Теперь, возможный способ устранить эту проблему:

foreach (var type in asmx.MainModule.Types) { 
     if (type.Name == "<Module>") continue; 
     foreach (var method in type.Methods) { 
      var cilWorker = method.Body.GetILProcessor(); 
      foreach (var il in ils) { 
       // grab method reference 
       var methodRef = il.Operand as Mono.Cecil.MethodReference; 
       if (methodRef != null) { 
        // if it belongs to another module 
        if (methodRef.Module.Name == (assemblyName + ".dll")) { 
         // resolve it back to method definition and then import, 
         // now to the correct module. Assign result back to opcode operand 
         il.Operand = asmx.MainModule.Import(methodRef.Resolve()); 
        } 
       } 

       cilWorker.Append(il); 
      } 
     } 
    } 

Тогда ваш код больше не будет бросать.

+0

Спасибо! хорошо исправить! –