-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
CA1869 is caused by a local instance of JsonSerializerOptions being created and used once as the options argument of a Serialize or Deserialize call as this can cause performance degradation if the code is executed multiple times.
I initially found this bug in a top-level program where there was only a single Deserialize call in the whole file, so I thought it was a little strange, but upon further investigation found that this bug extends to other situations.
Reproduction Steps
There are 3 versions, all very similar, but each with potentially different solutions.
Version 1 - Top-level program
JsonSerializerOptions options = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
var output = JsonSerializer.Deserialize<int[]>("[1,2,3]", options);Version 2 - In a class constructor:
public Test()
{
JsonSerializerOptions options = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
var output = JsonSerializer.Deserialize<int[]>("[1,2,3]", options);
}Version 3 - In a loop inside a standard method:
public void M()
{
for (int i = 0; i < 10; i++)
{
JsonSerializerOptions options = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
var output = JsonSerializer.Deserialize<int[]>("[1,2,3]", options);
}
}Expected behavior
For version 1, I'm honestly not sure what should happen - maybe nothing, as the fix appears to make the code worse, not better.
For version 2, I could see the fixer creating a static variable to hold the options for use in each construction.
For version 3, I would hope the fixer would, at the very least, move the instance creation outside the loop, as duplicating it inside the loop doesn't improve the performance at all.
Actual behavior
After using the provided fixer, the following was produced:
Version 1 - Top-level program
JsonSerializerOptions jsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
JsonSerializerOptions options = jsonSerializerOptions;
var output = JsonSerializer.Deserialize<int[]>("[1,2,3]", options);Version 2 - In a class constructor:
public Test()
{
JsonSerializerOptions jsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
JsonSerializerOptions options = jsonSerializerOptions;
var output = JsonSerializer.Deserialize<int[]>("[1,2,3]", options);Version 3 - In a loop inside a standard method:
public void M()
{
for (int i = 0; i < 10; i++)
{
JsonSerializerOptions jsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
JsonSerializerOptions options = jsonSerializerOptions;
var output = JsonSerializer.Deserialize<int[]>("[1,2,3]", options);
}
}Version 3 does also have an extra option, although after the one above, which alters the method to allow a JsonSerializerOptions instance to be passed in as a parameter, which is much better.
Regression?
The problem seems to also be in NET8, but not in NET7.
Known Workarounds
Ignore or suppress the rule.
Configuration
Using VS 17.13.0 Preview 4 in a NET9 console application, running on Windows 11 x64.
Other information
No response
