2016-11-28 1 views
2

Ich versuche, einen statischen Konstruktor Mono Cecil zu einem Programm wie folgt hinzuzufügen:statischen Konstruktor mit Mono.Cecil Hinzufügen verursacht TypeInitializationException

namespace SimpleTarget 
{ 
    class C 
    { 
     public void M() 
     { 
      Console.WriteLine("Hello, World!"); 
     } 
    } 
} 

Der folgende Code fügt den statischen Konstruktor:

namespace AddStaticConstructor 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var assemblyPath = args[0]; 
      var module = ModuleDefinition.ReadModule(assemblyPath); 

      var corlib = ModuleDefinition.ReadModule(typeof(object).Module.FullyQualifiedName); 
      var method = corlib.Types.First(t => t.Name.Equals("Console")).Methods.First(m => m.Name.Contains("WriteLine")); 

      var methodToCall = module.Import(method); 

      foreach (var type in module.Types) 
      { 
       if (!type.Name.Contains("C")) continue; 

       var staticConstructorAttributes = 
        Mono.Cecil.MethodAttributes.Private | 
        Mono.Cecil.MethodAttributes.HideBySig | 
        Mono.Cecil.MethodAttributes.Static | 
        Mono.Cecil.MethodAttributes.SpecialName | 
        Mono.Cecil.MethodAttributes.RTSpecialName; 

       MethodDefinition staticConstructor = new MethodDefinition(".cctor", staticConstructorAttributes, module.TypeSystem.Void); 
       type.Methods.Add(staticConstructor); 

       type.IsBeforeFieldInit = false; 

       var il = staticConstructor.Body.GetILProcessor(); 
       il.Append(Instruction.Create(OpCodes.Ret)); 

       Instruction ldMethodName = il.Create(OpCodes.Ldstr, type.FullName); 
       Instruction callOurMethod = il.Create(OpCodes.Call, methodToCall); 

       Instruction firstInstruction = staticConstructor.Body.Instructions[0]; 
       // Inserts the callOurMethod instruction before the first instruction 


       il.InsertBefore(firstInstruction, ldMethodName); 
       il.InsertAfter(ldMethodName, callOurMethod); 
      } 

      module.Write(assemblyPath); 
     } 
    } 
} 

Betrachtet man die dekompilierte Binärdatei in dotPeek, sieht es so aus, als wäre alles korrekt eingerichtet. Wenn ich versuche, den modifizierten C-Typ zu verwenden, erhalte ich eine TypeInitializationException mit der inneren Ausnahme "System.InvalidProgramException: JIT-Compiler hat eine interne Einschränkung gefunden"

Gibt es noch etwas, das ich richtig einstellen muss, bevor ich einen statischen Konstruktor benutze?

Danke!

+0

Bitte senden Sie uns eine [MCVE] . –

Antwort

2

Das Problem ist, dass Sie die falsche Überlastung von System.WriteLine hier bekommen:

var corlib = ModuleDefinition.ReadModule(typeof(object).Module.FullyQualifiedName); 
var method = corlib.Types.First(t => t.Name.Equals("Console")).Methods.First(m => m.Name.Contains("WriteLine")); 
var methodToCall = module.Import(method); 

Verwendung dieser einfachen Code die bekommen die Überlastung Sie verwenden möchten:

var wlMethod = typeof (Console).GetMethod(nameof(Console.WriteLine), new[] {typeof (string)}); 
var methodToCall = module.ImportReference(wlMethod); 
+0

Kein Mann, das ist nicht das Problem. Ja, es ist besser, es so zu schreiben, wie du es erwähnt hast, aber es wird auch so funktionieren, wie er es geschrieben hat. Er hat gerade die erste "WriteLine" -Methode, aber das ist egal, weil er kein Argument dafür abgegeben hat. –

+0

Sie müssen keine Strings speichern, die Sie mit 'ldstr' laden, Sie können sie einfach verwenden. – thehennyy

+0

Ja, wenn Sie es verwenden. Aber er tat es nicht. –

Verwandte Themen