使用Mono.Cecil发出对System.Lazy <T>构造函数的调用

Ben*_*Ben 8 .net mono.cecil

我正在尝试发出一个实例化System.Lazy并在PEVerify失败时出现"无效令牌"错误的方法 newobj instance void class [mscorlib]System.Lazy`1<class Example.ExpensiveType>::.ctor(class [mscorlib]System.Func`1<class Example.ExpensiveType>)

使用ILDasm查看其他地方,我看到正确的调用将如下所示:

newobj     instance void class [mscorlib]System.Lazy`1<class Example.IHeater>::.ctor(class [mscorlib]System.Func`1<!0>)
Run Code Online (Sandbox Code Playgroud)

不幸的是,我对如何使用Mono.Cecil API重现这一点感到茫然.有人可以帮助使用仿制药吗?

这是我到目前为止所拥有的:

var get = new MethodDefinition(
            "Get",
            MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
            ModuleDefinition.TypeSystem.Object);

var funcType = new GenericInstanceType(ImportedTypes.FuncOfT);
funcType.GenericArguments.Add(lazyElementType);

var funcTypeCtor = new MethodReference(".ctor", ModuleDefinition.TypeSystem.Void, funcType);
funcTypeCtor.Parameters.Add(new ParameterDefinition(ModuleDefinition.TypeSystem.Object));
funcTypeCtor.Parameters.Add(new ParameterDefinition(ModuleDefinition.TypeSystem.IntPtr));
funcTypeCtor.HasThis = true;
funcTypeCtor = ModuleDefinition.Import(funcTypeCtor);

var lazyTypeCtor = new MethodReference(".ctor", ModuleDefinition.TypeSystem.Void, lazyType);
var parameterDefinition = new ParameterDefinition(funcType);
lazyTypeCtor.Parameters.Add(parameterDefinition);
lazyTypeCtor.HasThis = true;
lazyTypeCtor = ModuleDefinition.Import(lazyTypeCtor);

il = get.Body.GetILProcessor();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldftn, getTypedValue);
il.Emit(OpCodes.Newobj, funcTypeCtor);
il.Emit(OpCodes.Newobj, lazyTypeCtor);  // This leads to the invalid token
il.Emit(OpCodes.Ret);
lazyBinding.Methods.Add(get);
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激 - 我很难过!

Ben*_*Ben 10

我已经发现了一个埋藏在一个多年的邮件列表档案中的答案(感谢GáborKozár!).我没有正确创建/导入泛型类型及其方法.正确加载Lazy<T>Func<T>类型的代码如下:

var genericArgument = lazyElementType;
var funcType = ModuleDefinition.Import(typeof(Func<>)).MakeGenericInstanceType(genericArgument);
var funcCtor =
    ModuleDefinition.Import(funcType.Resolve()
                                    .Methods.First(m => m.IsConstructor && m.Parameters.Count == 2))
                    .MakeHostInstanceGeneric(genericArgument);

var lazyType = ModuleDefinition.Import(typeof(Lazy<>)).MakeGenericInstanceType(genericArgument);
var lazyCtor =
    ModuleDefinition.Import(lazyType.Resolve()
                                    .GetConstructors()
                                    .First(m => m.Parameters.Count == 1
                                             && m.Parameters[0].ParameterType.Name.StartsWith("Func")))
                    .MakeHostInstanceGeneric(genericArgument);

// Method body as above
Run Code Online (Sandbox Code Playgroud)

上面的关键是扩展方法MakeHostInstanceGeneric,定义为

public static MethodReference MakeHostInstanceGeneric(
                                  this MethodReference self,
                                  params TypeReference[] args)
{
    var reference = new MethodReference(
        self.Name,
        self.ReturnType,
        self.DeclaringType.MakeGenericInstanceType(args))
    {
        HasThis = self.HasThis,
        ExplicitThis = self.ExplicitThis,
        CallingConvention = self.CallingConvention
    };

    foreach (var parameter in self.Parameters) {
        reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
    }

    foreach (var genericParam in self.GenericParameters) {
        reference.GenericParameters.Add(new GenericParameter(genericParam.Name, reference));
    }

    return reference;
}
Run Code Online (Sandbox Code Playgroud)