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
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 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.
is it possible to generate an eventhandler while running?
I want to do something like that:
public bool addCallback(string name, Delegate Callback)
{
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
//now I want to add an Eventhandler, which removes the Callback and this new Eventhandler itsself
return true;
}
(I am not 100% sure I understand what you are going to hook your generated event handler to from the example, but here's the easiest way I know of for creating an event handler)
Depends on your platform and trust level. The most flexible way of doing it is to use Emit to generate the method (see here).
However, I found a relatively easy to use and good alternative to be generated Linq expressions (here's the namespace help).
The idea is fairly simple:
Use the various Expression-derived classes you can see in the namespace to define what your callback is doing. In this case, you want to generate something that calls .RemoveEventHandler (I am guessing) on the ei instance (specifically, you will use the ConstantExpression to create a ref to your ei variable and to your Callback parameter and a MethodCallExpression to create a call to the RemoveDataHandler method).
Once you create the expression that does what you need, you need to create a delegate (Lambda) out of it (see here)
Almost done. You still need to compile the lambda, which you do by calling .Compile on the object you got from the previous step (see here)
Edit: This is a Windows console example of a dynamically generated delegate that removes itself. Note that WP7 Linq expression support is more limited than .NET 4.0 and so you will need to adjust it (make helper methods that will do some of the work and call them from the expression instead of what I did).
Edit2: BTW: The mechanism by which the lambda can remove itself, is to create another lambda that returns a local variable that is of that type. After creating the lambda, save it to the local variable and run the code (I am not sure if this would have worked without the secondary lambda)
Edit3: No - you have to use the delegate trick, otherwise, the constant gets "frozen" and will not update as you would want it to. So the code as is works.
public class MyEventArgs : EventArgs
{
}
public class EventContainer
{
public event EventHandler<MyEventArgs> MyEvent;
public void Fire()
{
Console.WriteLine("Firing");
if (MyEvent != null)
{
MyEvent(this, new MyEventArgs());
}
Console.WriteLine("Fired");
}
}
class Program
{
static void Main(string[] args)
{
EventContainer container = new EventContainer();
var adder = container.GetType().GetMethod("add_MyEvent");
var remover = container.GetType().GetMethod("remove_MyEvent");
object self = null;
Func<object> getSelf = () => self;
var block = Expression.Block(
// Call something to output to console.
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("Event called")),
// Now call the remove_Event method.
Expression.Call(
Expression.Constant(container), // passing the container as "this"
remover, // And the remover as the method info
Expression.Convert( // we need to cast the result of getSelf to the correct type to pass as an argument
Expression.Invoke( // For the parameter (what to convert), we need to call getSelf
Expression.Constant(getSelf)), // So this is a ref to getSelf
adder.GetParameters()[0].ParameterType) // finally, say what to convert to.
)
);
// Create a lambda of the correct type.
var lambda = Expression.Lambda(
adder.GetParameters()[0].ParameterType,
block,
Expression.Parameter(typeof(object)),
Expression.Parameter(typeof(MyEventArgs)));
var del = lambda.Compile();
// Make sure "self" knows what the delegate is (so our generated code can remove it)
self = del;
// Add the event.
adder.Invoke(container, new object[] { del });
// Fire once - see that delegate is being called.
container.Fire();
// Fire twice - see that the delegate was removed.
container.Fire();
}
}
public static bool addCallback(string name, Delegate Callback)
{
if (DataProxy == null)
GetDataProxy();
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
Type handlerType = ei.EventHandlerType;
MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
ParameterInfo[] parms = invokeMethod.GetParameters();
Type[] parmTypes = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
parmTypes[i] = parms[i].ParameterType;
}
List<ParameterExpression> parameters = new List<ParameterExpression>();
foreach(Type t in parmTypes)
{
parameters.Add(System.Linq.Expressions.Expression.Parameter(t));
}
ConstantExpression eventInfo = System.Linq.Expressions.Expression.Constant(ei, typeof(EventInfo));
ConstantExpression eventCallback = System.Linq.Expressions.Expression.Constant(Callback, typeof(Delegate));
ConstantExpression dataProxy = System.Linq.Expressions.Expression.Constant(DataProxy, typeof(MAServiceClient));
MethodCallExpression call = System.Linq.Expressions.Expression.Call(eventInfo, ei.GetType().GetMethod("RemoveEventHandler"), dataProxy, eventCallback);
//add to Expression.Body the call, which removes the new Eventhandler itsself
ei.AddEventHandler(DataProxy, System.Linq.Expressions.Expression.Lambda(ei.EventHandlerType, call, parameters).Compile());
return true;
}
This is what my method looks like right now. There is just one step missing, where the new Eventhandler (created by System.Linq.Expressions.Expression.Lambda(ei.EventHandlerType, call, parameters).Compile()) removes itsself (see comment).
Thanks to Shahar Prish I came up with the following code:
using ex = System.Linq.Expressions;
using System.Linq.Expressions;
public static bool addCallback(string name, Delegate Callback)
{
if (DataProxy == null)
GetDataProxy();
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
Type handlerType = ei.EventHandlerType;
MethodInfo removeMethod = ei.GetType().GetMethod("RemoveEventHandler");
MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
ParameterInfo[] parms = invokeMethod.GetParameters();
Type[] parmTypes = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
parmTypes[i] = parms[i].ParameterType;
}
List<ParameterExpression> parameters = new List<ParameterExpression>();
foreach(Type t in parmTypes)
{
parameters.Add(System.Linq.Expressions.Expression.Parameter(t));
}
Delegate self = null;
Func<Delegate> getSelf = () => self;
ConstantExpression eventInfo = ex.Expression.Constant(ei, typeof(EventInfo));
ConstantExpression eventCallback = ex.Expression.Constant(Callback, typeof(Delegate));
ConstantExpression dataProxy = ex.Expression.Constant(DataProxy, typeof(MAServiceClient));
MethodCallExpression removeCallback = ex.Expression.Call(eventInfo, removeMethod, dataProxy, eventCallback);
MethodCallExpression removeSelf = ex.Expression.Call(eventInfo, removeMethod, dataProxy, ex.Expression.Invoke(ex.Expression.Constant(getSelf)));
BlockExpression block = ex.Expression.Block(removeCallback, removeSelf);
LambdaExpression lambda = ex.Expression.Lambda(ei.EventHandlerType, block, parameters);
Delegate del = lambda.Compile();
self = del;
ei.AddEventHandler(DataProxy, del);
lambda = ex.Expression.Lambda(ei.EventHandlerType, block, parameters);
return true;
}
As I said before, this method should add the Eventhandler passed by Delegate Callback to the Event named string name of the static MAServiceClient DataProxy and remove it after it was called (and the Eventhandler which removes the Callback itsself).
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;