-
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
Support property ordering on POCOs #54748
Comments
Tagging subscribers to this area: @eiriktsarpalis, @layomia Issue DetailsBackground and MotivationAs part of making more extensible POCO converters and community asks, a low-risk feature for specifying ordering of properties\fields on a POCO for serialization is possible in the V6 timeframe. Other extensibility POCO features are no longer feasible for V6 since they need 1-2 preview releases to be properly vetted. Today the serializer depends on reflection order for properties, and does base classes afterwards. Reflection is currently not deterministic and control over base class ordering is desired. The simplest way to implement this is through an attribute that specifies the order. However, this only works for owned POCOs. For V7+ once the Note that Newtonsoft has a similar approach with The source-generator should also leverage this attribute. Proposed APInamespace System.Text.Json.Serialization
{
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class JsonPropertyOrderAttribute : JsonAttribute
+ {
+ public JsonPropertyNameAttribute(int order);
+ public int Order { get; }
+ }
} Usage Examplespublic class Person
{
[JsonPropertyOrder(-1)] // Always appear first
public int Id { get; set; }
[JsonPropertyOrder(1)] // appear before LastName
public string FirstName { get; set; }
[JsonPropertyOrder(2)]
public string LastName{ get; set; }
public string City{ get; set; } // No order defined (has a order value of 0)
} Alternative DesignsIt is possible to add a "strategy" pattern here, like we do for property naming. However, as mentioned in the introduction, in V7+ allowing write access to the
|
I think if someone wants to serialize base properties first it shouldn't be that tiresome as adding runtime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs Line 120 in 650f28f
|
Trying to understand the comment: Is |
in 728 I suggested to use a similar property ordering what Newtonsoft.Json is using, where -1 is the default value for the order if attribute is not explicitly defined. I think what @steveharter is proposing a +1 what Newtonsoft.json is doing, so 0 is the default (instead of -1), -1 is to force to be first (instead of -2). It might make sense to define a JsonPropertyFirst() attribute , instead of using a "weird" looking negative number |
Following offline discussion between @eiriktsarpalis and I, the proposal is to place no limitation on the integer values passed into the attribute ctor. If there are duplicates/ties, they'd be resolved by the serializer falling back to the reflection order (which would write props on derived classes first, before base). So props with order -3 would be written before -1, etc. |
We eventually want to allow this sort of imperative implementation, where STJ users can access the list of serializable properties and sort them themselves, using whatever sorting scheme they wish. This work isn't in scope for .NET 6.0, but is generally tracked by #34456. |
@layomia What do you think about a class Attribute to sort the props by name without individually setting the order value for each of them? props name sorting in this case should use the JsonPropertyNameAttribute for a prop if set.
|
namespace System.Text.Json.Serialization
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class JsonPropertyOrderAttribute : JsonAttribute
{
public JsonPropertyNameAttribute(int order);
public int Order { get; }
}
} |
I'm not sure I understand. Are you saying that the example from the original post will be written like this? public class Person
{
[JsonPropertyOrder(0)] // Always appear first
public int Id { get; set; }
[JsonPropertyOrder(int.MaxValue - 1)] // appear before LastName
public string FirstName { get; set; }
[JsonPropertyOrder(int.MaxValue)]
public string LastName{ get; set; }
public string City { get; set; } // No order defined
} To me, using -1, 1 and 2 (as originally proposed) is much clearer and it also doesn't require applying the attribute to all properties. |
The idea is: people generally don't care about the order of all the properties. For the subset they care, they might want to push them all the way to the top or all the way way to the end. Using By using a number that is neither public class AtTheBeginning
{
[JsonPropertyOrder(0)]
public int Id { get; set; }
[JsonPropertyOrder(1)]
public string FirstName { get; set; }
[JsonPropertyOrder(2)]
public string LastName{ get; set; }
// A bunch of properties which order I don't care for
}
public class AtTheEnd
{
// A bunch of properties which are sort of relevant, but I'm OK
// with alphabetic search
// Keep those two last:
[JsonPropertyOrder(ushort.MaxValue + 1)]
public string[] CustomKeys { get; set; }
[JsonPropertyOrder(ushort.MaxValue + 2)]
public string[] CustomValue { get; set; }
} Keeping things last is a bit of a fringe scenario, so having to know the magic default value seems fine. |
@terrajobst I think I understand now. With default 0, if you want to specify 1st, 2nd and 3rd item from the start, you would write them as -3, -2, -1 and that indeed isn't very intuitive, especially if that is the most common scenario. The magic default value could be fixed by introducing a separate constant for it, but that's probably not worth it. |
Here is a suggestion I have not heard being discussed during API review.
public class SomeClass
{
[JsonPropertyOrder(1)]
public string FirstName { get; set; } // Appears first
[JsonPropertyOrder(2)]
public string LastName{ get; set; } // Appears after first
// A bunch of properties which order we don't care for (default values)
[JsonPropertyOrder(0)]
public int Id { get; set; } // Same as default or not having the attribute
[JsonPropertyOrder(-2)]
public string Address{ get; set; } // Appears before the last one
[JsonPropertyOrder(-1)]
public string City{ get; set; } // Appears as the last one
} If a type has 5 properties and someone uses values 3 and -3 is a question, but should be able to settle in different ways. |
For the comments on the ordering, the intent was to allow all integer values (including negative) and sort the properties by order (e.g. from |
Background and Motivation
As part of making more extensible POCO converters and community asks, a low-risk feature for specifying ordering of properties\fields on a POCO for serialization is possible in the V6 timeframe. Other extensibility POCO features are no longer feasible for V6 since they need 1-2 preview releases to be properly vetted.
Today the serializer depends on reflection order for serializing object properties, and does base classes afterwards. Reflection is currently not deterministic and sometimes control over base class ordering is desired such as specifying base properties first.
The simplest way to implement this is through an attribute that specifies the order. However, this only works for owned POCOs. For V7+ once the
JsonPropertyInfo
is exposed publicly, that will allow for non-owned POCOs to also have this behavior.Note that Newtonsoft has a similar approach with
JsonPropertyAttribute.Order
.The source-generator should also leverage this attribute.
Proposed API
Usage Examples
If there is a "tie" in the values, the reflection order is used. This is also consistent with Newtsonsoft.
Alternative Designs
It is possible to add a "strategy" pattern here, like we do for property naming. However, as mentioned in the introduction, in V7+ allowing write access to the
JsonPropertyInfo.Order
property will likely be the most natural mechanism onceJsonPropertyInfo
is exposed publicly. This would be coupled with a mechanism to retrieve all properties, allowing, for example, properties to be sorted by base class first and\or sorted alphabetically without using[JsonPropertyOrder]
.The text was updated successfully, but these errors were encountered: