I have this method which wraps a constructor in a dynamic factory method:
static Func<TArg1, TResult> ToFactoryMethod<TArg1, TResult>(this ConstructorInfo ctor)
where TResult : class
{
var factoryMethod = new DynamicMethod(
name: string.Format("_{0:N}", Guid.NewGuid()),
returnType: typeof(TResult),
parameterTypes: new Type[] { typeof(TArg1) });
ILGenerator il = factoryMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Ret);
return (Func<TArg1, TResult>)
factoryMethod.CreateDelegate(typeof(Func<TArg1, TResult>));
}
However, the following code throws a VerificationException on the .Invoke(…):
ConstructorInfo ctor = typeof(Uri).GetConstructor(new Type[] { typeof(string) });
Func<string, Uri> uriFactory = ctor.ToFactoryMethod<string, Uri>();
Uri uri = uriFactory.Invoke("http://www.example.com");
The exception isn't thrown if I replace ldarg.1; newobj <ctor> with ldnull, so the problem must be caused by these two IL instructions. Further experiments suggest that the error lies with ldarg.1. (I've replaced this with a ldstr <string> for the specific example above.)
Does anyone see what's wrong with these IL instructions?
This method is static, so it doesn't have a this parameter as arg0. Changing il.Emit(OpCodes.Ldarg_1); by il.Emit(OpCodes.Ldarg_0); worked fine for me.
Related
I have an HelloWorld method with some logic in it. I have to generate many methods with different names that have same logic implemantation as HelloWorld. If HelloWorld method don't have any parameters it's easy to do. Problem starts when I have to pass some parameters to HelloWorld using DynamicMethod. Here is a pice of code to help you understand.
public string HelloWorld(string Greeting)
{
return Greeting;
}
public void MethodGenerator()
{
MethodInfo HelloWorldMethod = typeof(MyClass).GetMethod("HelloWorld");
DynamicMethod DM = new DynamicMethod("HelloWorld", typeof(string), new Type[] { typeof(MyClass) });
ILGenerator IL = DM.GetILGenerator();
IL.Emit(OpCodes.Ldarg_0);
IL.Emit(OpCodes.Call, HelloWorldMethod);
IL.Emit(OpCodes.Ret);
Func<MyClass, string> DMDelegate = (Func<MyClass, string>)DM.CreateDelegate(typeof(Func<MyClass, string>));
string Result = DMDelegate(MyObject);
}
Please help me to modify this code for my case. Thanks in advance.
P.S. I've already googled it, and didn't found anything for my case. Here are some google results that I used
Used Code example
Another example
I am trying to construct an instance of a generic type and call a method on that instance. Then return the result of the method.
MethodInfo methodInfo = ...;
...
var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Ldobj, methodInfo);
il.Emit(OpCodes.Callvirt, genericeClientHelper.GetMethod("MethodName", new Type[] { typeof(MethodInfo) }));
il.Emit(OpCodes.Ret);
I keep getting a 'System.BadImageFormatException: 'Bad class token.'' exception.
GenericType class looks like this
public class GenericType<T>
{
public T MethodName(MethodInfo methodInfo)
{
...
}
}
You're confusing the boundary between the generated program, and the generating program.
Specifically, your generating program, when run, constructs an instance of an object (a MethodInfo instance) and then attempts to generate a program that uses that instance - which it can't because that instance doesn't exist in the generated program, it exists in the memory of the generating program.
You have to construct the instance of MethodInfo inside your generated program - you have to write the Emit code to generate the IL that constructs the MethodInfo instance.
What you're trying to do makes about as much sense as doing the following:
Person person = new Person( "Antiduh", "United States" );
var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes));
// This doesn't make sense. The object referred to by
// my `person` variable doesn't exist in the generated program.
il.Emit(OpCodes.Ldobj, person);
il.Emit(OpCodes.Callvirt, genericeClientHelper.GetMethod("MethodName", new Type[] { typeof(MethodInfo) }));
il.Emit(OpCodes.Ret);
Thats problem number 1.
Problem number 2 is that you're using the wrong opcode when trying to provide an argument to a method - Ldobj doesn't do what you think it does.
Instead of using Ldobj, you'll have to load the reference by whatever means you fix your generation code to create the internal methodInfo. It'll probably be local, so you'll probably end up using Ldloc or some form thereof.
To come full circle, the reason why you're getting the error "Bad class token" is that the value that is supposed to follow Ldobj in the compiled IL is supposed to be a class metadata token. What you provided was not a class token, hence the error.
As a demonstration, below is a complete program that emulates what you're attempting to do.
private static void BuildAssembly()
{
AssemblyName assemblyName;
AssemblyBuilder assmBuilder;
ModuleBuilder modBuilder;
assemblyName = new AssemblyName( "Generated" );
// Note the save directory is the directory containing this project's solution file.
assmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.RunAndSave,
Assembly.GetExecutingAssembly().Location + #"\..\..\..\.."
);
modBuilder = assmBuilder.DefineDynamicModule(
assemblyName.Name,
assemblyName.Name + ".dll",
true
);
/*
* public class GenericsDemo {
* }
*/
TypeBuilder typeBuilder = modBuilder.DefineType(
"Generated.GenericsDemo",
TypeAttributes.Public
);
BuildCallListMethod( typeBuilder );
typeBuilder.CreateType();
assmBuilder.Save( assemblyName.Name + ".dll" );
}
private static void BuildCallListMethod( TypeBuilder typeBuilder )
{
// public void CallList() {
// List<object> list = new List<object>();
// object thing = new object();
// list.Add(thing);
// }
var listOfObject = typeof( List<object> );
var objType = typeof( object );
// public void CallList() {
var method = typeBuilder.DefineMethod(
"CallList",
MethodAttributes.Public | MethodAttributes.HideBySig,
CallingConventions.HasThis
);
var gen = method.GetILGenerator();
// List<int> list;
var listLocal = gen.DeclareLocal( listOfObject );
listLocal.SetLocalSymInfo( "list" );
// object thing;
var thingLocal = gen.DeclareLocal( objType );
thingLocal.SetLocalSymInfo( "thing" );
// list = new List<object>();
gen.Emit( OpCodes.Newobj, listOfObject.GetConstructor( Type.EmptyTypes ) );
gen.Emit( OpCodes.Stloc_0 );
// thing = new object();
gen.Emit( OpCodes.Newobj, objType.GetConstructor( Type.EmptyTypes ) );
gen.Emit( OpCodes.Stloc_1 );
// list.Add( thing );
gen.Emit( OpCodes.Ldloc_0 ); // loads `list`.
gen.Emit( OpCodes.Ldloc_1 ); // loads `thing`.
gen.EmitCall( OpCodes.Callvirt, listOfObject.GetMethod( "Add" ), null );
gen.Emit( OpCodes.Ret );
}
Hi guys I am trying to generate a delegate at runtime using Dynamic Methods and the ILGenerator to invoke the Setter of a property on an object.....
private static GenericIntSetter CreateIntSetMethod(PropertyInfo propertyInfo)
{
MethodInfo setMethod = propertyInfo.GetSetMethod();
if (setMethod == null)
return null;
Type[] arguments = new Type[2];
arguments[0] = typeof(Person);
arguments[1] = typeof(int);
DynamicMethod setter = new DynamicMethod(
String.Concat("_Set", propertyInfo.Name, "_"),
typeof(void), arguments, propertyInfo.DeclaringType);
ILGenerator generator = setter.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
generator.Emit(OpCodes.Ldarg_1);
if (propertyInfo.PropertyType.IsClass)
{
generator.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
}
else
{
generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
}
generator.EmitCall(OpCodes.Callvirt, setMethod, null);
generator.Emit(OpCodes.Ret);
return (GenericIntSetter)setter.CreateDelegate(typeof(GenericIntSetter));
}
When I call this method and I invoke the delete I get a corrupt memory error, any ideas?
Yep. It's really complicated to do that, but not impossible.
I have a open source project just for that http://mirrormirror.codeplex.com
In http://mirrormirror.codeplex.com/SourceControl/changeset/view/66562#869731 you will find the code for all the emit I need to do. It should be easy to find the setter implementation.
Hope it helps
I tried to generate IL for recursive method using following strategy,
Firstly I defined type using following code snippet
private void InitializeAssembly(string outputFileName)
{
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName assemblyName = new AssemblyName(outputFileName);
assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Save);
moduleBuilder = assemblyBuilder.DefineDynamicModule(outputFileName, outputFileName + ".exe");
typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
methodBuilder = typeBuilder.DefineMethod("Main",
MethodAttributes.Static | MethodAttributes.Public,
typeof(void),
System.Type.EmptyTypes);
ilGen = methodBuilder.GetILGenerator();
}
Next I started to generate IL for recursive method as given below.
MethodBuilder method = typeBuilder.DefineMethod(
“MethodName”,
MethodAttributes.Static | MethodAttributes.Public,
NodeTypeToDotNetType(func.RetType),
parameters);
ILGenerator ilOfMethod = method.GetILGenerator();
method.DefineParameter();
For calling method itself inside the method body I used following construct,
ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
Finally save generated assembly using following method.
private void SaveAssembly(string outputFileName)
{
ilGen.Emit(OpCodes.Ret);
typeBuilder.CreateType();
moduleBuilder.CreateGlobalFunctions();
assemblyBuilder.SetEntryPoint(methodBuilder);
assemblyBuilder.Save(outputFileName + ".exe");
}
Unfortunately this is not working since recursive method calling construct, inside the method returns null. Issue here is that recursive call inside the method ( i.e. ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
) returns null. Since we actually create the type inside the SaveAssembly() method, this is acceptable. So my question is that: is it possible to generate IL for recursive methods using above construct? If it is not possible, Please let me know that alternative constructs for generating IL for recursive methods.
I haven't tested it, but if I remember correctly you should be able to simply use the result of DefineMethod to emit the Call instruction:
MethodBuilder method = typeBuilder.DefineMethod("MethodName", ...);
...
ILGenerator ilOfMethod = method.GetILGenerator();
...
ilOfMethod.Emit(OpCodes.Call, method);
I am taking in an interface, looping through the .GetEvents() return array and attempting to implement the event on my dynamic type. At the point when I try to call TypeBuilder.CreateType(), I am greeted with this lovely error:
"Application method on type from assembly is overriding a method that has been overridden."
If I comment out the typeBuilder.DefineMethodOverride calls that attempt to implement the interface methods, at the poin when I attempt to subscribe to the event I get the error:
"The method or operation is not implemented."
Here is the method I have that is attempting to add the detected event to the emitted type. Just a quick note, I have other code defining the type and adding methods implementing those on the interface and all that code works fine. I had no problems until I attempted to add events into the mix.
protected static void AddEvent(EventInfo interfaceEvent, TypeBuilder proxyBuilder)
{
// Event methods attributes
MethodAttributes eventMethodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName;
MethodImplAttributes eventMethodImpAtr = MethodImplAttributes.Managed | MethodImplAttributes.Synchronized;
string qualifiedEventName = string.Format("{0}.{1}", typeof(T).Name, interfaceEvent.Name);
string addMethodName = string.Format("add_{0}", interfaceEvent.Name);
string remMethodName = string.Format("remove_{0}", interfaceEvent.Name);
FieldBuilder eFieldBuilder = proxyBuilder.DefineField(qualifiedEventName,
interfaceEvent.EventHandlerType, FieldAttributes.Public);
EventBuilder eBuilder = proxyBuilder.DefineEvent(qualifiedEventName, EventAttributes.None, interfaceEvent.EventHandlerType);
// ADD method
MethodBuilder addMethodBuilder = proxyBuilder.DefineMethod(addMethodName,
eventMethodAttr, null, new Type[] { interfaceEvent.EventHandlerType });
addMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
// We need the 'Combine' method from the Delegate type
MethodInfo combineInfo = typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) });
// Code generation
ILGenerator ilgen = addMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, combineInfo);
ilgen.Emit(OpCodes.Castclass, interfaceEvent.EventHandlerType);
ilgen.Emit(OpCodes.Stfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ret);
// REMOVE method
MethodBuilder removeMethodBuilder = proxyBuilder.DefineMethod(remMethodName,
eventMethodAttr, null, new Type[] { interfaceEvent.EventHandlerType });
removeMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
MethodInfo removeInfo = typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) });
// Code generation
ilgen = removeMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, removeInfo);
ilgen.Emit(OpCodes.Castclass, interfaceEvent.EventHandlerType);
ilgen.Emit(OpCodes.Stfld, eFieldBuilder);
ilgen.Emit(OpCodes.Ret);
// Finally, setting the AddOn and RemoveOn methods for our event
eBuilder.SetAddOnMethod(addMethodBuilder);
eBuilder.SetRemoveOnMethod(removeMethodBuilder);
// Implement the method from the interface
proxyBuilder.DefineMethodOverride(addMethodBuilder, typeof(T).GetMethod("add_" + interfaceEvent.Name));
// Implement the method from the interface
proxyBuilder.DefineMethodOverride(removeMethodBuilder, typeof(T).GetMethod("remove_" + interfaceEvent.Name));
}
Google has been 0 help on this (searching for "is overriding a method that has been overridden" just returns a lot of Crystal Reports topics), and I have been struggling with this all morning. Any help would be greatly appreciated!
Nevermind. When i loop through the method's of the interface to implement them I am accidentally implementing the add/remove also.
fixed it with this in my loop: if(method.IsSpecialName) continue;