-
Notifications
You must be signed in to change notification settings - Fork 5k
Cache polymorphic properties #41753
Cache polymorphic properties #41753
Changes from 1 commit
5d363fa
92b9b1e
2f0cf17
826bc61
df45181
e72ba56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,10 +2,11 @@ | |||||
// The .NET Foundation licenses this file to you under the MIT license. | ||||||
// See the LICENSE file in the project root for more information. | ||||||
|
||||||
using System.Collections.Generic; | ||||||
using System.Collections.Concurrent; | ||||||
using System.Diagnostics; | ||||||
using System.Reflection; | ||||||
using System.Text.Json.Serialization; | ||||||
using System.Threading; | ||||||
|
||||||
namespace System.Text.Json | ||||||
{ | ||||||
|
@@ -209,18 +210,26 @@ internal JsonPropertyInfo CreateRootObject(JsonSerializerOptions options) | |||||
options: options); | ||||||
} | ||||||
|
||||||
internal JsonPropertyInfo CreatePolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options) | ||||||
internal JsonPropertyInfo GetOrAddPolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options) | ||||||
{ | ||||||
JsonPropertyInfo runtimeProperty = CreateProperty( | ||||||
property.DeclaredPropertyType, runtimePropertyType, | ||||||
property.ImplementedPropertyType, | ||||||
property.PropertyInfo, | ||||||
parentClassType: Type, | ||||||
converter: null, | ||||||
options: options); | ||||||
property.CopyRuntimeSettingsTo(runtimeProperty); | ||||||
static JsonPropertyInfo CreateRuntimeProperty(Type runtimePropertyType, (JsonPropertyInfo property, JsonSerializerOptions options, Type classType) arg) | ||||||
{ | ||||||
JsonPropertyInfo runtimeProperty = CreateProperty( | ||||||
arg.property.DeclaredPropertyType, runtimePropertyType, | ||||||
arg.property.ImplementedPropertyType, | ||||||
arg.property.PropertyInfo, | ||||||
parentClassType: arg.classType, | ||||||
converter: null, | ||||||
options: arg.options); | ||||||
|
||||||
arg.property.CopyRuntimeSettingsTo(runtimeProperty); | ||||||
|
||||||
return runtimeProperty; | ||||||
} | ||||||
|
||||||
var cache = LazyInitializer.EnsureInitialized(ref property.RuntimePropertyCache, () => new ConcurrentDictionary<Type, JsonPropertyInfo>()); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this preferred over There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's preferred here, since
|
||||||
|
||||||
return runtimeProperty; | ||||||
return cache.GetOrAdd(runtimePropertyType, (type, arg) => CreateRuntimeProperty(type, arg), (property, options, Type)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @steveharter, unrelated to this PR, but here is some code cleanup we should consider (separately - out of scope for this PR which we should keep focused on the perf fix only):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is "ClassType" better? (somewhat redundant) Or just doc? The actual type can be a POCO type or any property type ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have a
|
||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -3,6 +3,7 @@ | |||
// See the LICENSE file in the project root for more information. | ||||
|
||||
using System.Collections; | ||||
using System.Collections.Concurrent; | ||||
using System.Diagnostics; | ||||
using System.Reflection; | ||||
using System.Text.Json.Serialization; | ||||
|
@@ -584,5 +585,7 @@ private void VerifyWrite(int originalDepth, Utf8JsonWriter writer) | |||
ThrowHelper.ThrowJsonException_SerializationConverterWrite(ConverterBase); | ||||
} | ||||
} | ||||
|
||||
public ConcurrentDictionary<Type, JsonPropertyInfo> RuntimePropertyCache; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be stored on the Also, can the following existing cache be used for the runtime properties as well? corefx/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs Line 23 in 437d9bc
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By storing the cache on the actual If we store the cache on a If we store the cache on a The cache in the current location of a So I think storing on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think that would be a good idea, since it would require allocating a string for every access to serve as the key. So you're likely paying lots of string allocations to avoid a single dictionary allocation. Just moving the cache to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @svick yes allocating a string for the key is not ideal, but small overhead compared to what we have today. A dictionary is heavy-weight so having one instance for a Type is much better than per property. However creating a new cache on |
||||
} | ||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,5 +75,12 @@ private class Indexer | |
|
||
public string NonIndexerProp { get; set; } | ||
} | ||
|
||
[Fact] | ||
public static void WriteCollectionAsObject() | ||
{ | ||
string json = JsonSerializer.Serialize(new { Prop = (object)new[] { 0 } }); | ||
Assert.Equal(@"{""Prop"":[0]}", json); | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add tests with different properties with the same |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Don't use var here.