Reputation: 26281
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
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
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