private AccessField <object, object?> EmitFieldAccessor(FieldDefinition fieldDefinition) { var method = new DynamicMethod( "AccessField", typeof(object), new[] { typeof(object).MakeByRefType() }, true); method.DefineParameter(1, ParameterAttributes.Out, "target"); var generator = method.GetRobustGen(); if (Type.IsValueType) { generator.DeclareLocal(Type); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldind_Ref); generator.Emit(OpCodes.Unbox_Any, Type); generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldloca_S, 0); } else { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldind_Ref); generator.Emit(OpCodes.Castclass, Type); } switch (fieldDefinition.BackingField) { case SpecificFieldInfo field: generator.Emit(OpCodes.Ldfld, field.FieldInfo); break; case SpecificPropertyInfo property: var getter = property.PropertyInfo.GetGetMethod(true) ?? throw new NullReferenceException(); var opCode = Type.IsValueType ? OpCodes.Call : OpCodes.Callvirt; generator.Emit(opCode, getter); break; } var returnType = fieldDefinition.BackingField.FieldType; if (returnType.IsValueType) { generator.Emit(OpCodes.Box, returnType); } generator.Emit(OpCodes.Ret); return(method.CreateDelegate <AccessField <object, object?> >()); }
private AssignField <object, object?> EmitFieldAssigner(FieldDefinition fieldDefinition) { var method = new DynamicMethod( "AssignField", typeof(void), new[] { typeof(object).MakeByRefType(), typeof(object) }, true); method.DefineParameter(1, ParameterAttributes.Out, "target"); method.DefineParameter(2, ParameterAttributes.None, "value"); var generator = method.GetRobustGen(); if (Type.IsValueType) { generator.DeclareLocal(Type); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldind_Ref); generator.Emit(OpCodes.Unbox_Any, Type); generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldloca, 0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Unbox_Any, fieldDefinition.FieldType); EmitSetField(generator, fieldDefinition.BackingField); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Box, Type); generator.Emit(OpCodes.Stind_Ref); generator.Emit(OpCodes.Ret); } else { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldind_Ref); generator.Emit(OpCodes.Castclass, Type); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Unbox_Any, fieldDefinition.FieldType); EmitSetField(generator, fieldDefinition.BackingField); generator.Emit(OpCodes.Ret); } return(method.CreateDelegate <AssignField <object, object?> >()); }