Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 3d73b19

Browse files
authored
Cache polymorphic properties (#41753) (#42057)
1 parent f91669a commit 3d73b19

File tree

6 files changed

+57
-14
lines changed

6 files changed

+57
-14
lines changed

src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Collections.Concurrent;
56
using System.Diagnostics;
67
using System.Reflection;
78
using System.Text.Json.Serialization;
9+
using System.Threading;
810

911
namespace System.Text.Json
1012
{
@@ -208,19 +210,31 @@ internal JsonPropertyInfo CreateRootObject(JsonSerializerOptions options)
208210
options: options);
209211
}
210212

211-
internal JsonPropertyInfo CreatePolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options)
213+
internal JsonPropertyInfo GetOrAddPolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options)
212214
{
213-
JsonPropertyInfo runtimeProperty = CreateProperty(
214-
property.DeclaredPropertyType,
215-
runtimePropertyType,
216-
property.ImplementedPropertyType,
217-
property.PropertyInfo,
218-
parentClassType: Type,
219-
converter: null,
220-
options: options);
221-
property.CopyRuntimeSettingsTo(runtimeProperty);
215+
static JsonPropertyInfo CreateRuntimeProperty((JsonPropertyInfo property, Type runtimePropertyType) key, (JsonSerializerOptions options, Type classType) arg)
216+
{
217+
JsonPropertyInfo runtimeProperty = CreateProperty(
218+
key.property.DeclaredPropertyType,
219+
key.runtimePropertyType,
220+
key.property.ImplementedPropertyType,
221+
key.property.PropertyInfo,
222+
parentClassType: arg.classType,
223+
converter : null,
224+
options: arg.options);
225+
226+
key.property.CopyRuntimeSettingsTo(runtimeProperty);
227+
228+
return runtimeProperty;
229+
}
222230

223-
return runtimeProperty;
231+
ConcurrentDictionary<(JsonPropertyInfo, Type), JsonPropertyInfo> cache =
232+
LazyInitializer.EnsureInitialized(ref RuntimePropertyCache, () => new ConcurrentDictionary<(JsonPropertyInfo, Type), JsonPropertyInfo>());
233+
#if BUILDING_INBOX_LIBRARY
234+
return cache.GetOrAdd((property, runtimePropertyType), (key, arg) => CreateRuntimeProperty(key, arg), (options, Type));
235+
#else
236+
return cache.GetOrAdd((property, runtimePropertyType), key => CreateRuntimeProperty(key, (options, Type)));
237+
#endif
224238
}
225239
}
226240
}

src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Collections;
6+
using System.Collections.Concurrent;
67
using System.Collections.Generic;
78
using System.Diagnostics;
89
using System.Reflection;
@@ -27,6 +28,9 @@ internal sealed partial class JsonClassInfo
2728
// All of the serializable properties on a POCO (except the optional extension property) keyed on property name.
2829
public volatile Dictionary<string, JsonPropertyInfo> PropertyCache;
2930

31+
// Serializable runtime/polymorphic properties, keyed on property and runtime type.
32+
public ConcurrentDictionary<(JsonPropertyInfo, Type), JsonPropertyInfo> RuntimePropertyCache;
33+
3034
// All of the serializable properties on a POCO including the optional extension property.
3135
// Used for performance during serialization instead of 'PropertyCache' above.
3236
public volatile JsonPropertyInfo[] PropertyCacheArray;

src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ private static void HandleStartArray(
3131
}
3232
else if (state.Current.JsonClassInfo.ClassType == ClassType.Unknown)
3333
{
34-
jsonPropertyInfo = state.Current.JsonClassInfo.CreatePolymorphicProperty(jsonPropertyInfo, typeof(object), options);
34+
jsonPropertyInfo = state.Current.JsonClassInfo.GetOrAddPolymorphicProperty(jsonPropertyInfo, typeof(object), options);
3535
}
3636

3737
// Verify that we have a valid enumerable.

src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleValue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private static void HandleValue(JsonTokenType tokenType, JsonSerializerOptions o
2424
}
2525
else if (state.Current.JsonClassInfo.ClassType == ClassType.Unknown)
2626
{
27-
jsonPropertyInfo = state.Current.JsonClassInfo.CreatePolymorphicProperty(jsonPropertyInfo, typeof(object), options);
27+
jsonPropertyInfo = state.Current.JsonClassInfo.GetOrAddPolymorphicProperty(jsonPropertyInfo, typeof(object), options);
2828
}
2929

3030
jsonPropertyInfo.Read(tokenType, ref state, ref reader);

src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ private static void GetRuntimePropertyInfo(object value, JsonClassInfo jsonClass
3131
// Nothing to do for typeof(object)
3232
if (runtimeType != typeof(object))
3333
{
34-
jsonPropertyInfo = jsonClassInfo.CreatePolymorphicProperty(jsonPropertyInfo, runtimeType, options);
34+
jsonPropertyInfo = jsonClassInfo.GetOrAddPolymorphicProperty(jsonPropertyInfo, runtimeType, options);
3535
}
3636
}
3737
}

src/System.Text.Json/tests/Serialization/Object.WriteTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,30 @@ public int this[int index]
7575

7676
public string NonIndexerProp { get; set; }
7777
}
78+
79+
[Fact]
80+
public static void WritePolymorhicSimple()
81+
{
82+
string json = JsonSerializer.Serialize(new { Prop = (object)new[] { 0 } });
83+
Assert.Equal(@"{""Prop"":[0]}", json);
84+
}
85+
86+
[Fact]
87+
public static void WritePolymorphicDifferentAttributes()
88+
{
89+
string json = JsonSerializer.Serialize(new Polymorphic());
90+
Assert.Equal(@"{""P1"":"""",""p_3"":""""}", json);
91+
}
92+
93+
private class Polymorphic
94+
{
95+
public object P1 => "";
96+
97+
[JsonIgnore]
98+
public object P2 => "";
99+
100+
[JsonPropertyName("p_3")]
101+
public object P3 => "";
102+
}
78103
}
79104
}

0 commit comments

Comments
 (0)