Call a call to the System.Lazy <T> constructor with Mono.Cecil

I am trying to emit a method that creates an instance of System.Lazy and with the PEVerify error "Invalid token" in the line newobj instance void class [mscorlib]System.Lazy`1<class Example.ExpensiveType>::.ctor(class [mscorlib]System.Func`1<class Example.ExpensiveType>)

Elsewhere with ILDasm, I see that the correct call would look like this:

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

Unfortunately, I do not understand how to reproduce this using the Mono.Cecil API. Can anyone help with generics?

Here is what I still have:

 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); 

Any help would be greatly appreciated - I'm at a standstill!

+7
source share
1 answer

I found the answer buried in a multi-year archive of mailing lists (thanks to Gabor Kozar!). I incorrectly created / imported generic types and their methods. The code that correctly loads the Lazy<T> and Func<T> types follows:

 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 

The key to the above is the MakeHostInstanceGeneric extension MakeHostInstanceGeneric , which is defined as

 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; } 
+9
source

All Articles