Добавление статического конструктора с помощью Mono.Cecil вызывает TypeInitializationException

Я пытаюсь добавить статический конструктор, используя Mono Cecil, в программу, подобную следующей:

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

Следующий код добавляет статический конструктор:

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);
        }
    }
}

Глядя на декомпилированный двоичный файл в dotPeek, кажется, что все настроено правильно. При попытке использовать модифицированный тип C я получаю TypeInitializationException с внутренним исключением «System.InvalidProgramException: компилятор JIT обнаружил внутреннее ограничение»

Есть ли что-то еще, что мне нужно правильно установить перед использованием статического конструктора?

Спасибо!


person Zooey    schedule 28.11.2016    source источник
comment
Опубликуйте минимально воспроизводимый пример.   -  person Lasse V. Karlsen    schedule 28.11.2016


Ответы (1)


Проблема в том, что здесь вы получаете неправильную перегрузку System.WriteLine:

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);

используйте этот простой код, чтобы получить перегрузку, которую вы хотите использовать:

var wlMethod = typeof (Console).GetMethod(nameof(Console.WriteLine), new[] {typeof (string)});
var methodToCall = module.ImportReference(wlMethod);
person thehennyy    schedule 28.11.2016
comment
Нет, чувак, проблема не в этом. Да, лучше написать так, как вы упомянули, но будет работать и так, как он написал. Он только что получил первый метод WriteLine, но это не имеет значения, потому что он не передал ему никаких аргументов. - person Dudi Keleti; 28.11.2016
comment
Вам не нужно хранить строки, которые вы загружаете с помощью ldstr, вы можете просто использовать их. - person thehennyy; 28.11.2016
comment
Да, если вы его используете. Но он этого не сделал. - person Dudi Keleti; 28.11.2016
comment
Теперь я тебя понимаю. Да вы пишите. Чтобы исправить это, он может сделать то, что я написал, или просто использовать это как ваш ответ. - person Dudi Keleti; 28.11.2016