dimanche 12 avril 2015

Using Reflection.Emit to set a property value

I'm building a dynamic proxy to intercept some methods within a library I am writing. I can successfully create my proxy type but when I try to implement the property setter I get the following error.



System.InvalidProgramException


Addition Information:


Common Language Runtime detected an invalid program.



My Emitter code is as follows:



public void Emit(FieldInfo interceptorField,
MethodInfo method,
TypeBuilder typeBuilder)
{
// Get the method parameters for any setters.
ParameterInfo[] parameters = method.GetParameters();
ParameterInfo parameter = parameters.FirstOrDefault();

// Define attributes.
const MethodAttributes MethodAttributes =
MethodAttributes.Public | MethodAttributes.HideBySig |
MethodAttributes.Virtual;

// Define the method.
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
method.Name,
MethodAttributes,
CallingConventions.HasThis,
method.ReturnType,
parameters.Select(param => param.ParameterType).ToArray());

ILGenerator il = methodBuilder.GetILGenerator();

// Set the correct flags to signal the property is managed
// and implemented in intermediate language.
methodBuilder.SetImplementationFlags(
MethodImplAttributes.Managed | MethodImplAttributes.IL);

// This is the equivalent to:
// IInterceptor interceptor = ((IProxy)this).Interceptor;
// if (interceptor == null)
// {
// throw new NotImplementedException();
// }
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, GetInterceptor);
Label skipThrow = il.DefineLabel();
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Bne_Un, skipThrow);
il.Emit(OpCodes.Newobj, NotImplementedConstructor);
il.Emit(OpCodes.Throw);
il.MarkLabel(skipThrow);

// This is equivalent to:
// For get
// return interceptor.Intercept(MethodBase.GetCurrentMethod(), null);
// For set
// interceptor.Intercept(MethodBase.GetCurrentMethod(), value);
il.Emit(OpCodes.Call, GetCurrentMethod);
il.Emit(parameter == null ? OpCodes.Ldnull : OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, InterceptorMethod);

if (method.ReturnType != typeof(void))
{
il.Emit(OpCodes.Ret);
}
}


When looking at the output code (A string property called Bat) using Telerik JustDecompile I get the following:



public override void set_Bat(string str)
{
IInterceptor interceptor = ((IProxy)this).Interceptor;
if (interceptor == null)
{
throw new NotImplementedException();
}
interceptor.Intercept(MethodBase.GetCurrentMethod(), str);
}


When using Reflector



public override void set_Bat(string str)
{
IInterceptor interceptor = ((IProxy)this).Interceptor;
if (interceptor == null)
{
throw new NotImplementedException();
}
}


Note how the last line is missing.


Any ideas?






Aucun commentaire:

Enregistrer un commentaire