Matias Cicero
Matias Cicero

Reputation: 26281

InvalidProgramException when trying to create a new type

I have the following code:

AssemblyBuilder newAssembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("CustomAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder newModule = newAssembly.DefineDynamicModule("CustomModule");
TypeBuilder newType = newModule.DefineType("CustomType", TypeAttributes.Public);
MethodBuilder newMethod = newType.DefineMethod("GetMessage", MethodAttributes.Public, typeof(string), Type.EmptyTypes);
byte[] methodBody = ((Func<string>)(() => "Hello, world!")).GetMethodInfo().GetMethodBody().GetILAsByteArray();
newMethod.CreateMethodBody(methodBody, methodBody.Length);
Type customType = newType.CreateType();
dynamic myObject = Activator.CreateInstance(customType);
string message = myObject.GetMessage();

However, an exception is thrown on the last line when tryingto call myObject.GetMessage():

InvalidProgramException - Common Language Runtime detected an invalid program.

What is wrong with my code and why is this exception being thrown?

Upvotes: 1

Views: 161

Answers (2)

elchido
elchido

Reputation: 153

The problem is that the lambda expression includes a string, which when compiled ends not with the method body but in the type's metadata. The ldstr instruction in the lambda refers to the string via a metadata token. When you get the IL bytes and copy then to the new method the ldstr in the new method will have an invalid metadata token.

Upvotes: 2

Kyle
Kyle

Reputation: 6684

If I had to hazard a guess, I'd say it's because of this line:

byte[] methodBody = ((Func<string>)(() => "Hello, world!")).GetMethodInfo().GetMethodBody().GetILAsByteArray();

I'm not sure exactly what signature (Func<string>)( () => "Hello, world!" ) will have, but it probably won't be the correct one (one accepting an implicit parameter of your defined type).

I'd recommend using the method builder's GetILGenerator method to do this:

AssemblyBuilder newAssembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("CustomAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder newModule = newAssembly.DefineDynamicModule("CustomModule");
TypeBuilder newType = newModule.DefineType("CustomType", TypeAttributes.Public);
MethodBuilder newMethod = newType.DefineMethod("GetMessage", MethodAttributes.Public, typeof(string), Type.EmptyTypes);

var il = newMethod.GetILGenerator();
// return "Hello, world!";
il.Emit( OpCodes.Ldstr, "Hello, world!" );
il.Emit( OpCodes.Ret );

Type customType = newType.CreateType();
dynamic myObject = Activator.CreateInstance(customType);
string message = myObject.GetMessage();

Upvotes: 1

Related Questions