Monday, September 13, 2010

Difference between reference type and value type

Consider the following example. You need to create a dynamic method with the following signature:
void SetValue(object instance, object value)
{
}

The method should set the given value to the specified property in the instance object. Property should be specified by its PropertyInfo.
Alas, Expressions in .NET 3.5 don't allow to create complex expressions and functors. So the solution is to use DynamicMethod from System.Reflection.Emit:

The code is create using ILDASM output:
private static Action<object, object> GenerateSetter(PropertyInfo property)
{
  DynamicMethod setter = new DynamicMethod("SetValue", null, new[] {typeof (object), typeof (object)});

  ILGenerator il = setter.GetILGenerator();

  il.Emit(OpCodes.Ldarg_0);
  il.Emit(OpCodes.Castclass, property.DeclaringType);
  il.Emit(OpCodes.Ldarg_1);
 
  il.Emit(OpCodes.Castclass, property.PropertyType);
 
  il.EmitCall(OpCodes.Callvirt, property.GetSetMethod(), null);
  il.Emit(OpCodes.Ret);

  setter.DefineParameter(0, ParameterAttributes.In, "instance");
  setter.DefineParameter(1, ParameterAttributes.In, "value");

  Action<object, object> result = (Action<object, object>) setter.CreateDelegate(typeof (Action<object, object>));
  return result;
}
 Alas, the highlighted line will cause System.Security.VerificationException: Operation could destabilize the runtime. exception. This is caused because reference types and value types use different casting operators: while reference types use cast, value types uses unboxing. So the highlighted line should be replaced with:
if (property.PropertyType.IsValueType)
  il.Emit(OpCodes.Unbox_Any, property.PropertyType);
else
  il.Emit(OpCodes.Castclass, property.PropertyType);

* This source code was highlighted with Source Code Highlighter.

2 comments:

  1. Mate, you can use OpCodes.Unbox_Any instead of OpCodes.Castclass in your example in the topic. Unbox_Any does the same work for reference type as the Castclass call.

    ReplyDelete
  2. Thank you for your comment. Yes, you're right. According to http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.unbox_any.aspx:
    "When applied to a reference type, the unbox.any instruction has the same effect as castclass"

    ReplyDelete