2013-05-08 15 views
7

我試圖發出實例化System.Lazy的方法,並與「無效令牌」的PEVerify錯誤而失敗,在該行newobj instance void class [mscorlib]System.Lazy`1<class Example.ExpensiveType>::.ctor(class [mscorlib]System.Func`1<class Example.ExpensiveType>)的Emit調用System.Lazy <T>構造與Mono.Cecil能

展望與其他地方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); 

任何幫助,將不勝感激 - 我難倒!

回答

9

我發現了一個埋在一個多年的郵件列表歸檔中的答案(感謝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 

關鍵上面是擴展方法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; 
}