【问题标题】:Emit call to System.Lazy<T> constructor with Mono.Cecil使用 Mono.Cecil 发出对 System.Lazy<T> 构造函数的调用
【发布时间】:2013-05-02 02:37:18
【问题描述】:

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

使用 ILDasm 寻找其他地方,我发现正确的调用如下所示:

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

不幸的是,我不知道如何使用 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);

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

【问题讨论】:

    标签: .net mono.cecil


    【解决方案1】:

    我在一个多年前的邮件列表存档中找到了答案(感谢 Gábor Kozár!)。我没有正确创建/导入泛型类型及其方法。正确加载Lazy&lt;T&gt;Func&lt;T&gt; 类型的代码如下:

    var genericArgument = lazyElementType;
    var funcType = ModuleDefinition.ImportReference(typeof(Func<>)).MakeGenericInstanceType(genericArgument);
    var funcCtor =
        ModuleDefinition.ImportReference(funcType.Resolve()
                                        .Methods.First(m => m.IsConstructor && m.Parameters.Count == 2))
                        .MakeHostInstanceGeneric(genericArgument);
    
    var lazyType = ModuleDefinition.ImportReference(typeof(Lazy<>)).MakeGenericInstanceType(genericArgument);
    var lazyCtor =
        ModuleDefinition.ImportReference(lazyType.Resolve()
                                        .GetConstructors()
                                        .First(m => m.Parameters.Count == 1
                                                 && m.Parameters[0].ParameterType.Name.StartsWith("Func")))
                        .MakeHostInstanceGeneric(genericArgument);
    
    // Method body as above
    

    上面的关键是扩展方法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;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-08-10
      • 2014-01-10
      • 1970-01-01
      • 2020-05-18
      • 2011-10-14
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多