Skip to content

Commit dbcb819

Browse files
authored
Devirtualized default value comparison (#37674)
* Devirtualized default value comparison * Fixed double comparison for ref types * Fixed serialization * Addressed issues
1 parent dd41a4a commit dbcb819

File tree

2 files changed

+31
-37
lines changed

2 files changed

+31
-37
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
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.Generic;
65
using System.Diagnostics;
76
using System.Diagnostics.CodeAnalysis;
87
using System.Runtime.CompilerServices;
@@ -76,8 +75,6 @@ internal override sealed JsonParameterInfo CreateJsonParameterInfo()
7675
/// </summary>
7776
internal bool IsInternalConverter { get; set; }
7877

79-
internal readonly EqualityComparer<T> _defaultComparer = EqualityComparer<T>.Default;
80-
8178
// This non-generic API is sealed as it just forwards to the generic version.
8279
internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options, ref WriteStack state)
8380
{

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

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
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.Generic;
56
using System.Diagnostics;
67
using System.Reflection;
7-
using System.Runtime.CompilerServices;
88
using System.Text.Json.Serialization;
99

1010
namespace System.Text.Json
@@ -16,8 +16,6 @@ namespace System.Text.Json
1616
/// or a type's converter, if the current instance is a <see cref="JsonClassInfo.PropertyInfoForClassInfo"/>.
1717
internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
1818
{
19-
private static readonly T s_defaultValue = default!;
20-
2119
public Func<object, T>? Get { get; private set; }
2220
public Action<object, T>? Set { get; private set; }
2321

@@ -97,44 +95,45 @@ public override JsonConverter ConverterBase
9795

9896
public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
9997
{
100-
bool success;
10198
T value = Get!(obj);
10299

100+
// Since devirtualization only works in non-shared generics,
101+
// the default comparer is uded only for value types for now.
102+
// For reference types there is a quick check for null.
103+
if (IgnoreDefaultValuesOnWrite && (
104+
default(T) == null ? value == null : EqualityComparer<T>.Default.Equals(default, value)))
105+
{
106+
return true;
107+
}
108+
103109
if (value == null)
104110
{
105-
Debug.Assert(s_defaultValue == null && Converter.CanBeNull);
111+
Debug.Assert(Converter.CanBeNull);
106112

107-
success = true;
108-
if (!IgnoreDefaultValuesOnWrite)
113+
if (Converter.HandleNull)
109114
{
110-
if (!Converter.HandleNull)
115+
// No object, collection, or re-entrancy converter handles null.
116+
Debug.Assert(Converter.ClassType == ClassType.Value);
117+
118+
if (state.Current.PropertyState < StackFramePropertyState.Name)
111119
{
112-
writer.WriteNullSection(EscapedNameSection);
120+
state.Current.PropertyState = StackFramePropertyState.Name;
121+
writer.WritePropertyNameSection(EscapedNameSection);
113122
}
114-
else
123+
124+
int originalDepth = writer.CurrentDepth;
125+
Converter.Write(writer, value, Options);
126+
if (originalDepth != writer.CurrentDepth)
115127
{
116-
// No object, collection, or re-entrancy converter handles null.
117-
Debug.Assert(Converter.ClassType == ClassType.Value);
118-
119-
if (state.Current.PropertyState < StackFramePropertyState.Name)
120-
{
121-
state.Current.PropertyState = StackFramePropertyState.Name;
122-
writer.WritePropertyNameSection(EscapedNameSection);
123-
}
124-
125-
int originalDepth = writer.CurrentDepth;
126-
Converter.Write(writer, value, Options);
127-
if (originalDepth != writer.CurrentDepth)
128-
{
129-
ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter);
130-
}
128+
ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter);
131129
}
132130
}
133-
}
134-
else if (IgnoreDefaultValuesOnWrite && Converter._defaultComparer.Equals(s_defaultValue, value))
135-
{
136-
Debug.Assert(s_defaultValue != null && !Converter.CanBeNull);
137-
success = true;
131+
else
132+
{
133+
writer.WriteNullSection(EscapedNameSection);
134+
}
135+
136+
return true;
138137
}
139138
else
140139
{
@@ -144,10 +143,8 @@ public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf
144143
writer.WritePropertyNameSection(EscapedNameSection);
145144
}
146145

147-
success = Converter.TryWrite(writer, value, Options, ref state);
146+
return Converter.TryWrite(writer, value, Options, ref state);
148147
}
149-
150-
return success;
151148
}
152149

153150
public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer)
@@ -179,7 +176,7 @@ public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref U
179176
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Converter.TypeToConvert);
180177
}
181178

182-
Debug.Assert(s_defaultValue == null);
179+
Debug.Assert(default(T) == null);
183180

184181
if (!IgnoreDefaultValuesOnRead)
185182
{

0 commit comments

Comments
 (0)