Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,18 @@ private void GenerateFastPathFuncForObject(SourceWriter writer, ContextGeneratio
? $"(({propertyGenSpec.DeclaringType.FullyQualifiedName}){ValueVarName})"
: ValueVarName;

string propValueExpr = $"{objectExpr}.{propertyGenSpec.NameSpecifiedInSourceCode}";
string propValueExpr;
if (defaultCheckType != DefaultCheckType.None)
{
// Use temporary variable to evaluate property value only once
string localVariableName = $"__value_{propertyGenSpec.NameSpecifiedInSourceCode}";
writer.WriteLine($"{propertyGenSpec.PropertyType.FullyQualifiedName} {localVariableName} = {objectExpr}.{propertyGenSpec.NameSpecifiedInSourceCode};");
propValueExpr = localVariableName;
}
else
{
propValueExpr = $"{objectExpr}.{propertyGenSpec.NameSpecifiedInSourceCode}";
}

switch (defaultCheckType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ public class CustomWrappingResolver<T> : IJsonTypeInfoResolver

[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(JsonMessage))]
[JsonSerializable(typeof(AllocatingOnPropertyAccess))]
public partial class FastPathSerializationContext : JsonSerializerContext
{ }

Expand Down Expand Up @@ -816,5 +817,22 @@ public TestResolver(Func<Type, JsonSerializerOptions, JsonTypeInfo?> getTypeInfo

public JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options) => _getTypeInfo(type, options);
}

[Fact]
public static void FastPathSerialization_EvaluatePropertyOnlyOnceWhenIgnoreNullOrDefaultIsSpecified()
{
JsonSerializerOptions options = FastPathSerializationContext.Default.Options;
JsonTypeInfo<AllocatingOnPropertyAccess> allocatingOnPropertyAccessInfo = (JsonTypeInfo<AllocatingOnPropertyAccess>)options.GetTypeInfo(typeof(AllocatingOnPropertyAccess));
Assert.NotNull(allocatingOnPropertyAccessInfo.SerializeHandler);

var value = new AllocatingOnPropertyAccess();
Assert.Equal(0, value.WhenWritingNullAccessCounter);
Assert.Equal(0, value.WhenWritingDefaultAccessCounter);

string expectedJson = """{"SomeAllocatingProperty":"Current Value: 1","SomeAllocatingProperty2":"Current Value: 1"}""";
Assert.Equal(expectedJson, JsonSerializer.Serialize(value, options));
Assert.Equal(1, value.WhenWritingNullAccessCounter);
Assert.Equal(1, value.WhenWritingDefaultAccessCounter);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ public class JsonMessage
public int Length => Message?.Length ?? 0; // Read-only property
}

public class AllocatingOnPropertyAccess
{
public int WhenWritingNullAccessCounter = 0;
public int WhenWritingDefaultAccessCounter = 0;

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string SomeAllocatingProperty => $"Current Value: {++WhenWritingNullAccessCounter}";

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string SomeAllocatingProperty2 => $"Current Value: {++WhenWritingDefaultAccessCounter}";
}

internal struct MyStruct { }

public struct PersonStruct
Expand Down