lundi 26 juillet 2021

Replacing a class field's value via IL

In my effort to learn and understand IL I'm trying to replace the value of a private field in an object, however it's not working.

public class Example
{
    private int _value;
}

private delegate void _memberUpdaterByRef(ref object source, object value);
private _memberUpdaterByRef GetWriterForField(FieldInfo field)
{
    // dynamically generate a new method that will emit IL to set a field value
    var type = field.DeclaringType;
    var dynamicMethod = new DynamicMethod(
        $"Set{field.Name}",
        typeof(void),
        new Type[] { typeof(object).MakeByRefType(), typeof(object) },
        type.Module,
        true
    );

    var gen = dynamicMethod.GetILGenerator();

    var typedSource = gen.DeclareLocal(field.DeclaringType);
    gen.Emit(OpCodes.Ldarg_0); // Load the instance of the object (argument 0) onto the stack
    gen.Emit(OpCodes.Ldind_Ref); // load as a reference type
    gen.Emit(OpCodes.Unbox_Any, field.DeclaringType);
    gen.Emit(OpCodes.Stloc_0); // pop typed arg0 into temp

    gen.Emit(OpCodes.Ldloca_S, typedSource);
    gen.Emit(OpCodes.Ldarg_1); // Load the instance of the object (argument 1) onto the stack
    gen.Emit(OpCodes.Unbox_Any, field.FieldType);
    gen.Emit(OpCodes.Stfld, field);

    gen.Emit(OpCodes.Ldarg_0); // Load the instance of the object (argument 0) onto the stack
    gen.Emit(OpCodes.Ldloc_0); // push temp
    gen.Emit(OpCodes.Box, field.DeclaringType);
    gen.Emit(OpCodes.Stind_Ref); // store object reference
    gen.Emit(OpCodes.Ret); // return void

    // create a delegate matching the parameter types
    return (_memberUpdaterByRef)dynamicMethod.CreateDelegate(typeof(_memberUpdaterByRef));
}

Given the following pseudo-code, the private field named _value does not change:

// field = Example._value
var writer = GetWriterForField(field);
writer(ref newInstance, 100); // Example._value = 0

I'm not really sure how to debug this, or what is incorrect about my IL syntax. I'm pretty much learning IL and grabbing bits from different sources trying to get this to work.





Aucun commentaire:

Enregistrer un commentaire