-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stable Dictionary sorting for System.Text.Json #76008
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsSerializing the same dictionary but with entries added in different order in STJ can result in different results every time you run your app. We should offer converter/option which can make this behavior stable. Repro: using System.Text.Json;
Test repro = new Test();
if (Environment.TickCount % 2 == 0)
{
repro.Dict.Add("left", "foo");
repro.Dict.Add("right", "bar");
}
else
{
repro.Dict.Add("right", "bar");
repro.Dict.Add("left", "foo");
}
Console.WriteLine(JsonSerializer.Serialize(repro));
public class Test
{
public Dictionary<string, string> Dict { get; } = new();
} Output (randomly one of the following two):
or
Expected output:
|
Enumeration order of dictionary entries is generally speaking nondeterministic, and that is reflected by how entries get serialized in JSON. I can see how certain users might expect deterministic ordering, but there needs to be a commonly agreed upon order: should we sort by string keys? What if the key type is not a string? Is there prior art in this space? Does Json.NET offer similar functionality? |
Probably the biggest use of this isn't for reader-side enumeration. |
Should we be sorting by key? What about supported dictionary keys that are not strings? NB the default order of a key type might not be monotonic w.r.t. its JSON serialization, for example |
yes, it's mostly about the serialized JSON being same for same entries, not about particular order. IMO unless there isn't anything builtin to give some defaults we should support at least string keys and maybe couple of numeric types. Possibly make sort func customizable through resolver but not necessarily |
FWIW the CBOR specification defines a conformance mode mandating that map/object encodings are sorted lowest-to-highest by their key encodings. It might be worth investigating whether such a mode exists in the JSON space and whether we might consider supporting that out of the box. |
Maybe users should just use a dictionary type that provides stable order? |
@GSPP it is a good workaround but in general consider following scenario:
Another scenario: |
I can see that having deterministic ordering including when round-tripping the JSON would sometimes be useful. However, if the code for the object being serialized can be changed, the corresponding dictionary type could be changed to
FWIW |
I have worked for a company where this was being relied on in about 1000 places. Unfortunately, it doesn't fully work even when just adding. There are some conditions that I forgot. I believe starting at about 1000 items it breaks down. I think there also was a problem with rehashing in case of too many collisions (a security feature). In any case, I do not believe that relying on this should be encouraged as an unofficial workaround (not that you would have suggested otherwise). There should be a "correct" official guidance on how to achieve this scenario. I also believe that sorting keys is often inadequate. Yes, it does ensure determinism. But it also alters the natural order of items which could be meaningful. It can be semantically meaningful, but it also might have debugging value. |
The problem is that usually you want a stable key-based sort specifically for those cases where items were inserted in different orders for whatever reason. Insertion order being irrelevant to the serialized document. |
This has come up for me as well while implementing the While the public class JsonSerializerOptions
{
// ...
public IComparer<string> KeyOrdering { get; set; }
} Just as as idea. This way I can specify how I want to sort the keys, be it ordinal, or ignore case, or whatever. |
It sounds like a setting you'd want to specify on individual properties, not as global configuration. |
Not sure what you mean, @eiriktsarpalis. I'd definitely want this on an entire single serialization. |
I'm not saying a global flag wouldn't be useful, but I can also see cases where such a blanket policy might be undesirable. FWIW we support key serialization beyond just strings (admittedly that's not as common though). Shouldn't the setting account for those as well? |
Sure. I'm just saying that I think an open-ended option would be a good solution for this. I'm not set on it being |
Serializing the same dictionary but with entries added in different order in STJ can result in different results every time you run your app. We should offer converter/option which can make this behavior stable.
Repro:
Output (randomly one of the following two):
or
Expected output:
The text was updated successfully, but these errors were encountered: