在使用Mono.Cecil添加静态构造函数时导致TypeInitializationException异常

3
我正在尝试使用Mono Cecil向类似以下程序添加静态构造函数:
```

code

```
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编译器遇到了内部限制”。

在使用静态构造函数之前,我是否还需要设置其他内容?

谢谢!


请发布一个 [mcve]。 - Lasse V. Karlsen
1个回答

3
问题在于你在这里使用了错误的 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);

不,这不是问题。是的,像你所提到的那样写更好,但他写的方式也可以工作。他只是使用了第一个“WriteLine”方法,但这并不重要,因为他没有传递任何参数给它。 - Dudi Keleti
你不必存储使用 ldstr 加载的字符串,直接使用即可。 - thehennyy
是的,如果您使用它。但他没有。 - Dudi Keleti
现在我明白你的意思了。是的,你写得对。要修复它,他可以按照我写的方法去做,或者直接使用你的答案。 - Dudi Keleti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接