I\'m trying to emit a method that instantiates a System.Lazy and failing with a PEVerify error of \"Invalid token\", at the line newobj instance void class [mscorl
I've discovered the answer buried in a years-old mailing list archive (thanks to Gábor Kozár!). I was not properly creating/importing generic types and their methods. The code that properly loads the Lazy
and Func
types follows:
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
Key to the above is the extension method 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;
}