【问题标题】:Adding static constructor with Mono.Cecil causes TypeInitializationException使用 Mono.Cecil 添加静态构造函数会导致 TypeInitializationException
【发布时间】:2016-11-28 16:20:16
【问题描述】:

我正在尝试将使用 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 类型时,我得到一个带有内部异常“System.InvalidProgramException:JIT 编译器遇到内部限制”的 TypeInitializationException

在使用静态构造函数之前我还需要正确设置什么吗?

谢谢!

【问题讨论】:

标签: c# cil mono.cecil


【解决方案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);

【讨论】:

  • 不,这不是问题。是的,最好像你提到的那样写,但它也会像他写的那样工作。他刚刚得到了第一个WriteLine 方法,但这并不重要,因为他没有向它传递任何参数。
  • 您不必存储使用ldstr 加载的字符串,您可以直接使用它们。
  • 是的,如果你使用它。但他没有。
  • 现在我理解你了。是的,你写。为了解决这个问题,他可以做我写的,或者像你的回答一样使用它。
猜你喜欢
  • 2014-01-10
  • 2011-02-24
  • 1970-01-01
  • 1970-01-01
  • 2012-12-13
  • 2013-06-24
  • 2011-03-01
  • 1970-01-01
  • 2012-05-04
相关资源
最近更新 更多