<PackageReference Include="System.Text.Json" Version="9.0.0-preview.7.24405.7" />

ReflectionEmitMemberAccessor

using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; namespace System.Text.Json.Serialization.Metadata { internal sealed class ReflectionEmitMemberAccessor : MemberAccessor { [RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")] [RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")] public ReflectionEmitMemberAccessor() { } public override Func<object> CreateParameterlessConstructor(Type type, ConstructorInfo constructorInfo) { if (type.IsAbstract) return null; if ((object)constructorInfo == null && !type.IsValueType) return null; DynamicMethod dynamicMethod = new DynamicMethod(ConstructorInfo.ConstructorName, JsonTypeInfo.ObjectType, Type.EmptyTypes, typeof(ReflectionEmitMemberAccessor).Module, true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); if ((object)constructorInfo == null) { LocalBuilder local = iLGenerator.DeclareLocal(type); iLGenerator.Emit(OpCodes.Ldloca_S, local); iLGenerator.Emit(OpCodes.Initobj, type); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Box, type); } else { iLGenerator.Emit(OpCodes.Newobj, constructorInfo); if (type.IsValueType) iLGenerator.Emit(OpCodes.Box, type); } iLGenerator.Emit(OpCodes.Ret); return CreateDelegate<Func<object>>(dynamicMethod); } public override Func<object[], T> CreateParameterizedConstructor<T>(ConstructorInfo constructor) { return CreateDelegate<Func<object[], T>>(CreateParameterizedConstructor(constructor)); } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] private static DynamicMethod CreateParameterizedConstructor(ConstructorInfo constructor) { Type declaringType = constructor.DeclaringType; ParameterInfo[] parameters = constructor.GetParameters(); int num = parameters.Length; DynamicMethod dynamicMethod = new DynamicMethod(ConstructorInfo.ConstructorName, declaringType, new Type[1] { typeof(object[]) }, typeof(ReflectionEmitMemberAccessor).Module, true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); for (int i = 0; i < num; i++) { Type parameterType = parameters[i].ParameterType; iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldc_I4, i); iLGenerator.Emit(OpCodes.Ldelem_Ref); iLGenerator.Emit(OpCodes.Unbox_Any, parameterType); } iLGenerator.Emit(OpCodes.Newobj, constructor); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3> CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor) { return CreateDelegate<JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>>(CreateParameterizedConstructor(constructor, typeof(TArg0), typeof(TArg1), typeof(TArg2), typeof(TArg3))); } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] private static DynamicMethod CreateParameterizedConstructor(ConstructorInfo constructor, Type parameterType1, Type parameterType2, Type parameterType3, Type parameterType4) { Type declaringType = constructor.DeclaringType; int num = constructor.GetParameters().Length; DynamicMethod dynamicMethod = new DynamicMethod(ConstructorInfo.ConstructorName, declaringType, new Type[4] { parameterType1, parameterType2, parameterType3, parameterType4 }, typeof(ReflectionEmitMemberAccessor).Module, true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); for (int i = 0; i < num; i++) { ILGenerator iLGenerator2 = iLGenerator; OpCode opcode; switch (i) { case 0: opcode = OpCodes.Ldarg_0; break; case 1: opcode = OpCodes.Ldarg_1; break; case 2: opcode = OpCodes.Ldarg_2; break; case 3: opcode = OpCodes.Ldarg_3; break; default: throw new InvalidOperationException(); } iLGenerator2.Emit(opcode); } iLGenerator.Emit(OpCodes.Newobj, constructor); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Action<TCollection, object> CreateAddMethodDelegate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TCollection>() { return CreateDelegate<Action<TCollection, object>>(CreateAddMethodDelegate(typeof(TCollection))); } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] private static DynamicMethod CreateAddMethodDelegate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type collectionType) { MethodInfo methodInfo = collectionType.GetMethod("Push") ?? collectionType.GetMethod("Enqueue"); DynamicMethod dynamicMethod = new DynamicMethod(methodInfo.Name, typeof(void), new Type[2] { collectionType, JsonTypeInfo.ObjectType }, typeof(ReflectionEmitMemberAccessor).Module, true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Func<IEnumerable<TElement>, TCollection> CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>() { return CreateDelegate<Func<IEnumerable<TElement>, TCollection>>(CreateImmutableEnumerableCreateRangeDelegate(typeof(TCollection), typeof(TElement), typeof(IEnumerable<TElement>))); } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "The constructor has been marked RequiresUnreferencedCode")] private static DynamicMethod CreateImmutableEnumerableCreateRangeDelegate(Type collectionType, Type elementType, Type enumerableType) { MethodInfo immutableEnumerableCreateRangeMethod = collectionType.GetImmutableEnumerableCreateRangeMethod(elementType); DynamicMethod dynamicMethod = new DynamicMethod(immutableEnumerableCreateRangeMethod.Name, collectionType, new Type[1] { enumerableType }, typeof(ReflectionEmitMemberAccessor).Module, true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Call, immutableEnumerableCreateRangeMethod); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection> CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>() { return CreateDelegate<Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection>>(CreateImmutableDictionaryCreateRangeDelegate(typeof(TCollection), typeof(TKey), typeof(TValue), typeof(IEnumerable<KeyValuePair<TKey, TValue>>))); } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "The constructor has been marked RequiresUnreferencedCode")] private static DynamicMethod CreateImmutableDictionaryCreateRangeDelegate(Type collectionType, Type keyType, Type valueType, Type enumerableType) { MethodInfo immutableDictionaryCreateRangeMethod = collectionType.GetImmutableDictionaryCreateRangeMethod(keyType, valueType); DynamicMethod dynamicMethod = new DynamicMethod(immutableDictionaryCreateRangeMethod.Name, collectionType, new Type[1] { enumerableType }, typeof(ReflectionEmitMemberAccessor).Module, true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Call, immutableDictionaryCreateRangeMethod); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Func<object, TProperty> CreatePropertyGetter<TProperty>(PropertyInfo propertyInfo) { return CreateDelegate<Func<object, TProperty>>(CreatePropertyGetter(propertyInfo, typeof(TProperty))); } private static DynamicMethod CreatePropertyGetter(PropertyInfo propertyInfo, Type runtimePropertyType) { MethodInfo getMethod = propertyInfo.GetMethod; Type declaringType = propertyInfo.DeclaringType; Type propertyType = propertyInfo.PropertyType; DynamicMethod dynamicMethod = CreateGetterMethod(propertyInfo.Name, runtimePropertyType); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); if (declaringType.IsValueType) { iLGenerator.Emit(OpCodes.Unbox, declaringType); iLGenerator.Emit(OpCodes.Call, getMethod); } else { iLGenerator.Emit(OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Callvirt, getMethod); } if (propertyType != runtimePropertyType && propertyType.IsValueType) iLGenerator.Emit(OpCodes.Box, propertyType); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Action<object, TProperty> CreatePropertySetter<TProperty>(PropertyInfo propertyInfo) { return CreateDelegate<Action<object, TProperty>>(CreatePropertySetter(propertyInfo, typeof(TProperty))); } private static DynamicMethod CreatePropertySetter(PropertyInfo propertyInfo, Type runtimePropertyType) { MethodInfo setMethod = propertyInfo.SetMethod; Type declaringType = propertyInfo.DeclaringType; Type propertyType = propertyInfo.PropertyType; DynamicMethod dynamicMethod = CreateSetterMethod(propertyInfo.Name, runtimePropertyType); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(declaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Ldarg_1); if (propertyType != runtimePropertyType && propertyType.IsValueType) iLGenerator.Emit(OpCodes.Unbox_Any, propertyType); iLGenerator.Emit(declaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, setMethod); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Func<object, TProperty> CreateFieldGetter<TProperty>(FieldInfo fieldInfo) { return CreateDelegate<Func<object, TProperty>>(CreateFieldGetter(fieldInfo, typeof(TProperty))); } private static DynamicMethod CreateFieldGetter(FieldInfo fieldInfo, Type runtimeFieldType) { Type declaringType = fieldInfo.DeclaringType; Type fieldType = fieldInfo.FieldType; DynamicMethod dynamicMethod = CreateGetterMethod(fieldInfo.Name, runtimeFieldType); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(declaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Ldfld, fieldInfo); if (fieldType.IsValueType && fieldType != runtimeFieldType) iLGenerator.Emit(OpCodes.Box, fieldType); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } public override Action<object, TProperty> CreateFieldSetter<TProperty>(FieldInfo fieldInfo) { return CreateDelegate<Action<object, TProperty>>(CreateFieldSetter(fieldInfo, typeof(TProperty))); } private static DynamicMethod CreateFieldSetter(FieldInfo fieldInfo, Type runtimeFieldType) { Type declaringType = fieldInfo.DeclaringType; Type fieldType = fieldInfo.FieldType; DynamicMethod dynamicMethod = CreateSetterMethod(fieldInfo.Name, runtimeFieldType); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(declaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Ldarg_1); if (fieldType != runtimeFieldType && fieldType.IsValueType) iLGenerator.Emit(OpCodes.Unbox_Any, fieldType); iLGenerator.Emit(OpCodes.Stfld, fieldInfo); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod; } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] private static DynamicMethod CreateGetterMethod(string memberName, Type memberType) { return new DynamicMethod(memberName + "Getter", memberType, new Type[1] { JsonTypeInfo.ObjectType }, typeof(ReflectionEmitMemberAccessor).Module, true); } [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "The constructor has been marked RequiresDynamicCode")] private static DynamicMethod CreateSetterMethod(string memberName, Type memberType) { return new DynamicMethod(memberName + "Setter", typeof(void), new Type[2] { JsonTypeInfo.ObjectType, memberType }, typeof(ReflectionEmitMemberAccessor).Module, true); } [return: NotNullIfNotNull("method")] private static T CreateDelegate<T>(DynamicMethod method) where T : Delegate { return (T)(method?.CreateDelegate(typeof(T))); } } }