<PackageReference Include="System.Text.Json" Version="6.0.0-rc.1.21451.13" />

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 { public override JsonTypeInfo.ConstructorDelegate CreateConstructor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) { ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); if (type.IsAbstract) return null; if (constructor == (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 (constructor == (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, constructor); iLGenerator.Emit(OpCodes.Ret); return (JsonTypeInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonTypeInfo.ConstructorDelegate)); } public override Func<object[], T> CreateParameterizedConstructor<T>(ConstructorInfo constructor) { return CreateDelegate<Func<object[], T>>(CreateParameterizedConstructor(constructor)); } private static DynamicMethod CreateParameterizedConstructor(ConstructorInfo constructor) { Type declaringType = constructor.DeclaringType; ParameterInfo[] parameters = constructor.GetParameters(); int num = parameters.Length; if (num > 64) return null; 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_S, 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))); } private static DynamicMethod CreateParameterizedConstructor(ConstructorInfo constructor, Type parameterType1, Type parameterType2, Type parameterType3, Type parameterType4) { Type declaringType = constructor.DeclaringType; ParameterInfo[] parameters = constructor.GetParameters(); int num = parameters.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))); } 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; } [RequiresUnreferencedCode("System.Collections.Immutable converters use Reflection to find and create Immutable Collection types, which requires unreferenced code.")] public override Func<IEnumerable<TElement>, TCollection> CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>() { return CreateDelegate<Func<IEnumerable<TElement>, TCollection>>(CreateImmutableEnumerableCreateRangeDelegate(typeof(TCollection), typeof(TElement), typeof(IEnumerable<TElement>))); } [RequiresUnreferencedCode("System.Collections.Immutable converters use Reflection to find and create Immutable Collection types, which requires unreferenced code.")] 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; } [RequiresUnreferencedCode("System.Collections.Immutable converters use Reflection to find and create Immutable Collection types, which requires unreferenced code.")] 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>>))); } [RequiresUnreferencedCode("System.Collections.Immutable converters use Reflection to find and create Immutable Collection types, which requires unreferenced code.")] 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; } private static DynamicMethod CreateGetterMethod(string memberName, Type memberType) { return new DynamicMethod(memberName + "Getter", memberType, new Type[1] { JsonTypeInfo.ObjectType }, typeof(ReflectionEmitMemberAccessor).Module, true); } 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))); } } }