Let\'s say I have the following code which update a field of a struct using reflection. Since the struct instance is copied into the DynamicUpdate
After some experiments:
public delegate void ClassFieldSetter(T target, TValue value) where T : class;
public delegate void StructFieldSetter(ref T target, TValue value) where T : struct;
public static class FieldSetterCreator
{
public static ClassFieldSetter CreateClassFieldSetter(FieldInfo field)
where T : class
{
return CreateSetter>(field);
}
public static StructFieldSetter CreateStructFieldSetter(FieldInfo field)
where T : struct
{
return CreateSetter>(field);
}
private static TDelegate CreateSetter(FieldInfo field)
{
return (TDelegate)(object)CreateSetter(field, typeof(T), typeof(TValue), typeof(TDelegate));
}
private static Delegate CreateSetter(FieldInfo field, Type instanceType, Type valueType, Type delegateType)
{
if (!field.DeclaringType.IsAssignableFrom(instanceType))
throw new ArgumentException("The field is declared it different type");
if (!field.FieldType.IsAssignableFrom(valueType))
throw new ArgumentException("The field type is not assignable from the value");
var paramType = instanceType.IsValueType ? instanceType.MakeByRefType() : instanceType;
var setter = new DynamicMethod("", typeof(void),
new[] { paramType, valueType },
field.DeclaringType.Module, true);
var generator = setter.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
return setter.CreateDelegate(delegateType);
}
}
The main difference from the expression tree approach is that readonly fields can also be changed.