|
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace DomeCreator.CommandBehaviour
{
/// <summary>
/// Generates delegates according to the specified signature on runtime
/// </summary>
public static class EventHandlerGenerator
{
/// <summary>
/// Generates a delegate with a matching signature of the supplied eventHandlerType
/// This method only supports Events that have a delegate of type void
/// </summary>
/// <param name="eventInfo">The delegate type to wrap. Note that this must always be a void delegate</param>
/// <param name="methodToInvoke">The method to invoke</param>
/// <param name="methodInvoker">The object where the method resides</param>
/// <returns>Returns a delegate with the same signature as eventHandlerType that calls the methodToInvoke inside</returns>
public static Delegate CreateDelegate(Type eventHandlerType, MethodInfo methodToInvoke, object methodInvoker)
{
//Get the eventHandlerType signature
var eventHandlerInfo = eventHandlerType.GetMethod("Invoke");
Type returnType = eventHandlerInfo.ReturnParameter.ParameterType;
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type. This only supprts event handlers that are void");
ParameterInfo[] delegateParameters = eventHandlerInfo.GetParameters();
//Get the list of type of parameters. Please note that we do + 1 because we have to push the object where the method resides i.e methodInvoker parameter
Type[] hookupParameters = new Type[delegateParameters.Length + 1];
hookupParameters[0] = methodInvoker.GetType();
for (int i = 0; i < delegateParameters.Length; i++)
hookupParameters[i + 1] = delegateParameters[i].ParameterType;
DynamicMethod handler = new DynamicMethod("", null,
hookupParameters, typeof(EventHandlerGenerator));
ILGenerator eventIL = handler.GetILGenerator();
//load the parameters or everything will just BAM :)
LocalBuilder local = eventIL.DeclareLocal(typeof(object[]));
eventIL.Emit(OpCodes.Ldc_I4, delegateParameters.Length + 1);
eventIL.Emit(OpCodes.Newarr, typeof(object));
eventIL.Emit(OpCodes.Stloc, local);
//start from 1 because the first item is the instance. Load up all the arguments
for (int i = 1; i < delegateParameters.Length + 1; i++)
{
eventIL.Emit(OpCodes.Ldloc, local);
eventIL.Emit(OpCodes.Ldc_I4, i);
eventIL.Emit(OpCodes.Ldarg, i);
eventIL.Emit(OpCodes.Stelem_Ref);
}
eventIL.Emit(OpCodes.Ldloc, local);
//Load as first argument the instance of the object for the methodToInvoke i.e methodInvoker
eventIL.Emit(OpCodes.Ldarg_0);
//Now that we have it all set up call the actual method that we want to call for the binding
eventIL.EmitCall(OpCodes.Call, methodToInvoke, null);
eventIL.Emit(OpCodes.Pop);
eventIL.Emit(OpCodes.Ret);
//create a delegate from the dynamic method
return handler.CreateDelegate(eventHandlerType, methodInvoker);
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.