Skip to content

Commit d80a09f

Browse files
Fix a linker warning with the JsonSerializerOptionsUpdateHandler (#100362)
* * Fixes a linker warning with JsonSerializerOptionsUpdateHandler. * Makes a few cleanups in the MemberAccessor clases. * Ensures that the MemberAccessor being used is a singleton. * Fix a number of trimmability warnings.
1 parent a5b9a6a commit d80a09f

File tree

6 files changed

+115
-75
lines changed

6 files changed

+115
-75
lines changed

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptionsUpdateHandler.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5-
using System.Diagnostics.CodeAnalysis;
65
using System.Reflection.Metadata;
7-
using System.Runtime.CompilerServices;
86
using System.Text.Json;
97
using System.Text.Json.Serialization.Metadata;
108

@@ -25,11 +23,7 @@ public static void ClearCache(Type[]? types)
2523
options.Key.ClearCaches();
2624
}
2725

28-
if (RuntimeFeature.IsDynamicCodeSupported)
29-
{
30-
// Flush the dynamic method cache
31-
ReflectionEmitCachingMemberAccessor.Clear();
32-
}
26+
DefaultJsonTypeInfoResolver.ClearMemberAccessorCaches();
3327
}
3428
}
3529
}

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,38 @@
77
using System.Reflection;
88
using System.Runtime.CompilerServices;
99
using System.Text.Json.Reflection;
10+
using System.Threading;
1011

1112
namespace System.Text.Json.Serialization.Metadata
1213
{
1314
public partial class DefaultJsonTypeInfoResolver
1415
{
1516
internal static MemberAccessor MemberAccessor
1617
{
18+
[RequiresUnreferencedCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
1719
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
1820
get
1921
{
20-
return s_memberAccessor ??=
22+
return s_memberAccessor ?? Initialize();
23+
static MemberAccessor Initialize()
24+
{
25+
MemberAccessor value =
2126
#if NETCOREAPP
22-
// if dynamic code isn't supported, fallback to reflection
23-
RuntimeFeature.IsDynamicCodeSupported ?
24-
new ReflectionEmitCachingMemberAccessor() :
25-
new ReflectionMemberAccessor();
27+
// if dynamic code isn't supported, fallback to reflection
28+
RuntimeFeature.IsDynamicCodeSupported ?
29+
new ReflectionEmitCachingMemberAccessor() :
30+
new ReflectionMemberAccessor();
2631
#elif NETFRAMEWORK
27-
new ReflectionEmitCachingMemberAccessor();
32+
new ReflectionEmitCachingMemberAccessor();
2833
#else
29-
new ReflectionMemberAccessor();
34+
new ReflectionMemberAccessor();
3035
#endif
36+
return Interlocked.CompareExchange(ref s_memberAccessor, value, null) ?? value;
37+
}
3138
}
3239
}
3340

41+
internal static void ClearMemberAccessorCaches() => s_memberAccessor?.Clear();
3442
private static MemberAccessor? s_memberAccessor;
3543

3644
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/MemberAccessor.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,16 @@ namespace System.Text.Json.Serialization.Metadata
99
{
1010
internal abstract class MemberAccessor
1111
{
12-
public abstract Func<object>? CreateParameterlessConstructor(
13-
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type,
14-
ConstructorInfo? constructorInfo);
12+
public abstract Func<object>? CreateParameterlessConstructor(Type type, ConstructorInfo? constructorInfo);
1513

1614
public abstract Func<object[], T> CreateParameterizedConstructor<T>(ConstructorInfo constructor);
1715

18-
public abstract JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
19-
CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor);
16+
public abstract JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>? CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor);
2017

2118
public abstract Action<TCollection, object?> CreateAddMethodDelegate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TCollection>();
2219

23-
[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
24-
[RequiresDynamicCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
2520
public abstract Func<IEnumerable<TElement>, TCollection> CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>();
2621

27-
[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
28-
[RequiresDynamicCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
2922
public abstract Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection> CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>();
3023

3124
public abstract Func<object, TProperty> CreatePropertyGetter<TProperty>(PropertyInfo propertyInfo);
@@ -35,5 +28,7 @@ public abstract JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, T
3528
public abstract Func<object, TProperty> CreateFieldGetter<TProperty>(FieldInfo fieldInfo);
3629

3730
public abstract Action<object, TProperty> CreateFieldSetter<TProperty>(FieldInfo fieldInfo);
31+
32+
public virtual void Clear() { }
3833
}
3934
}

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitCachingMemberAccessor.cs

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,54 +8,70 @@
88

99
namespace System.Text.Json.Serialization.Metadata
1010
{
11-
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
1211
internal sealed partial class ReflectionEmitCachingMemberAccessor : MemberAccessor
1312
{
14-
private static readonly ReflectionEmitMemberAccessor s_sourceAccessor = new();
15-
private static readonly Cache<(string id, Type declaringType, MemberInfo? member)> s_cache =
16-
new(slidingExpiration: TimeSpan.FromMilliseconds(1000), evictionInterval: TimeSpan.FromMilliseconds(200));
13+
private readonly ReflectionEmitMemberAccessor _sourceAccessor;
14+
private readonly Cache<(string id, Type declaringType, MemberInfo? member)> _cache;
1715

18-
public static void Clear() => s_cache.Clear();
16+
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
17+
[RequiresUnreferencedCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
18+
public ReflectionEmitCachingMemberAccessor()
19+
{
20+
_sourceAccessor = new ReflectionEmitMemberAccessor();
21+
_cache = new(slidingExpiration: TimeSpan.FromMilliseconds(1000), evictionInterval: TimeSpan.FromMilliseconds(200));
22+
}
1923

20-
public override Action<TCollection, object?> CreateAddMethodDelegate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TCollection>()
21-
=> s_cache.GetOrAdd((nameof(CreateAddMethodDelegate), typeof(TCollection), null),
22-
static (_) => s_sourceAccessor.CreateAddMethodDelegate<TCollection>());
24+
public override void Clear() => _cache.Clear();
2325

24-
public override Func<object>? CreateParameterlessConstructor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, ConstructorInfo? ctorInfo)
25-
=> s_cache.GetOrAdd((nameof(CreateParameterlessConstructor), type, ctorInfo),
26-
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2077:UnrecognizedReflectionPattern",
27-
Justification = "Cannot apply DynamicallyAccessedMembersAttribute to tuple properties.")]
28-
#pragma warning disable IL2077 // The suppression doesn't work for the trim analyzer: https://github.com/dotnet/roslyn/issues/59746
29-
static (key) => s_sourceAccessor.CreateParameterlessConstructor(key.declaringType, (ConstructorInfo?)key.member));
30-
#pragma warning restore IL2077
26+
public override Action<TCollection, object?> CreateAddMethodDelegate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TCollection>() =>
27+
_cache.GetOrAdd(
28+
key: (nameof(CreateAddMethodDelegate), typeof(TCollection), null),
29+
_ => _sourceAccessor.CreateAddMethodDelegate<TCollection>());
3130

32-
public override Func<object, TProperty> CreateFieldGetter<TProperty>(FieldInfo fieldInfo)
33-
=> s_cache.GetOrAdd((nameof(CreateFieldGetter), typeof(TProperty), fieldInfo), static key => s_sourceAccessor.CreateFieldGetter<TProperty>((FieldInfo)key.member!));
31+
public override Func<object>? CreateParameterlessConstructor(Type type, ConstructorInfo? ctorInfo) =>
32+
_cache.GetOrAdd(
33+
key: (nameof(CreateParameterlessConstructor), type, ctorInfo),
34+
valueFactory: key => _sourceAccessor.CreateParameterlessConstructor(key.declaringType, (ConstructorInfo?)key.member));
3435

35-
public override Action<object, TProperty> CreateFieldSetter<TProperty>(FieldInfo fieldInfo)
36-
=> s_cache.GetOrAdd((nameof(CreateFieldSetter), typeof(TProperty), fieldInfo), static key => s_sourceAccessor.CreateFieldSetter<TProperty>((FieldInfo)key.member!));
36+
public override Func<object, TProperty> CreateFieldGetter<TProperty>(FieldInfo fieldInfo) =>
37+
_cache.GetOrAdd(
38+
key: (nameof(CreateFieldGetter), typeof(TProperty), fieldInfo),
39+
valueFactory: key => _sourceAccessor.CreateFieldGetter<TProperty>((FieldInfo)key.member!));
3740

38-
[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
39-
public override Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection> CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>()
40-
=> s_cache.GetOrAdd((nameof(CreateImmutableDictionaryCreateRangeDelegate), typeof((TCollection, TKey, TValue)), null),
41-
static (_) => s_sourceAccessor.CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>());
41+
public override Action<object, TProperty> CreateFieldSetter<TProperty>(FieldInfo fieldInfo) =>
42+
_cache.GetOrAdd(
43+
key: (nameof(CreateFieldSetter), typeof(TProperty), fieldInfo),
44+
valueFactory: key => _sourceAccessor.CreateFieldSetter<TProperty>((FieldInfo)key.member!));
4245

43-
[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
44-
public override Func<IEnumerable<TElement>, TCollection> CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>()
45-
=> s_cache.GetOrAdd((nameof(CreateImmutableEnumerableCreateRangeDelegate), typeof((TCollection, TElement)), null),
46-
static (_) => s_sourceAccessor.CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>());
46+
public override Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection> CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>() =>
47+
_cache.GetOrAdd(
48+
key: (nameof(CreateImmutableDictionaryCreateRangeDelegate), typeof((TCollection, TKey, TValue)), null),
49+
valueFactory: _ => _sourceAccessor.CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>());
4750

48-
public override Func<object[], T> CreateParameterizedConstructor<T>(ConstructorInfo constructor)
49-
=> s_cache.GetOrAdd((nameof(CreateParameterizedConstructor), typeof(T), constructor), static key => s_sourceAccessor.CreateParameterizedConstructor<T>((ConstructorInfo)key.member!));
51+
public override Func<IEnumerable<TElement>, TCollection> CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>() =>
52+
_cache.GetOrAdd(
53+
key: (nameof(CreateImmutableEnumerableCreateRangeDelegate), typeof((TCollection, TElement)), null),
54+
valueFactory: _ => _sourceAccessor.CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>());
5055

51-
public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>? CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor)
52-
=> s_cache.GetOrAdd((nameof(CreateParameterizedConstructor), typeof(T), constructor), static key => s_sourceAccessor.CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>((ConstructorInfo)key.member!));
56+
public override Func<object[], T> CreateParameterizedConstructor<T>(ConstructorInfo constructor) =>
57+
_cache.GetOrAdd(
58+
key: (nameof(CreateParameterizedConstructor), typeof(T), constructor),
59+
valueFactory: key => _sourceAccessor.CreateParameterizedConstructor<T>((ConstructorInfo)key.member!));
5360

54-
public override Func<object, TProperty> CreatePropertyGetter<TProperty>(PropertyInfo propertyInfo)
55-
=> s_cache.GetOrAdd((nameof(CreatePropertyGetter), typeof(TProperty), propertyInfo), static key => s_sourceAccessor.CreatePropertyGetter<TProperty>((PropertyInfo)key.member!));
61+
public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>? CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor) =>
62+
_cache.GetOrAdd(
63+
key: (nameof(CreateParameterizedConstructor), typeof(T), constructor),
64+
valueFactory: key => _sourceAccessor.CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>((ConstructorInfo)key.member!));
5665

57-
public override Action<object, TProperty> CreatePropertySetter<TProperty>(PropertyInfo propertyInfo)
58-
=> s_cache.GetOrAdd((nameof(CreatePropertySetter), typeof(TProperty), propertyInfo), static key => s_sourceAccessor.CreatePropertySetter<TProperty>((PropertyInfo)key.member!));
66+
public override Func<object, TProperty> CreatePropertyGetter<TProperty>(PropertyInfo propertyInfo) =>
67+
_cache.GetOrAdd(
68+
key: (nameof(CreatePropertyGetter), typeof(TProperty), propertyInfo),
69+
valueFactory: key => _sourceAccessor.CreatePropertyGetter<TProperty>((PropertyInfo)key.member!));
70+
71+
public override Action<object, TProperty> CreatePropertySetter<TProperty>(PropertyInfo propertyInfo) =>
72+
_cache.GetOrAdd(
73+
key: (nameof(CreatePropertySetter), typeof(TProperty), propertyInfo),
74+
valueFactory: key => _sourceAccessor.CreatePropertySetter<TProperty>((PropertyInfo)key.member!));
5975
}
6076
}
6177
#endif

0 commit comments

Comments
 (0)