dimanche 30 avril 2017

Getting a property value using IL for a struct

I'm trying to retrieve a value from the following struct.

public struct T
{
    public string Key { get; set; }
    public string Value { get; set; }
}

using the following code.

var mem = new MemberAccessor(r.GetType(), "Value");
object s = mem.Get(r);

And it works, but it gives me the value of "Key" not "Value". If I try this trying to get the value of "Key" then it gives me a "Cannot read from memory" error.

The following is the creation of the Get delegate used in the above code. This only appears to be a problem with a struct.

    private Func<object, object> GetGetDelegate()
    {
        Type[] setParamTypes = new[] { typeof(object) };
        Type setReturnType = typeof(object);

        Type owner = _targetType.GetTypeInfo().IsAbstract || _targetType.GetTypeInfo().IsInterface ? null : _targetType;
        var getMethod = owner != null
            ? new DynamicMethod(Guid.NewGuid().ToString(), setReturnType, setParamTypes, owner, true)
            : new DynamicMethod(Guid.NewGuid().ToString(), setReturnType, setParamTypes, true);

        ILGenerator getIL = getMethod.GetILGenerator();

        getIL.DeclareLocal(typeof(object));
        getIL.Emit(OpCodes.Ldarg_0); //Load the first argument
        //Cast to the source type
        getIL.Emit(OpCodes.Castclass, this._targetType);

        //Get the property value

        if (IsField(_member))
        {
            getIL.Emit(OpCodes.Ldfld, (FieldInfo)_member);
            if (_memberType.GetTypeInfo().IsValueType)
            {
                getIL.Emit(OpCodes.Box, _memberType);
            }
        }
        else
        {
            var targetGetMethod = ((PropertyInfo)_member).GetGetMethod();
            getIL.Emit(OpCodes.Callvirt, targetGetMethod);
            if (targetGetMethod.ReturnType.GetTypeInfo().IsValueType)
            {
                getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType);
            }
        }

        getIL.Emit(OpCodes.Ret);

        var del = getMethod.CreateDelegate(Expression.GetFuncType(setParamTypes.Concat(new[] { setReturnType }).ToArray()));
        return del as Func<object, object>;
    }





Aucun commentaire:

Enregistrer un commentaire