.NET核心3:JsonPropertyName的序列化顺序(System.Text.Json.Serialization) - c#

迁移到.NET Core 3时,我已经从Newtonsoft.Json序列化切换到System.Text.Json.Serialization。在所有功能中,我想继续使用JsonPropertyName属性。

Newtonsoft版本允许ordering of serialized attributes:

[JsonProperty(Order = 1)]
public bool Deleted { get; set; }

[JsonProperty(Order = 2)]
public DateTime DeletedDate { get; set; }

有没有办法在System.Text.Json.Serialization中实现相同的目的?

c#大神给出的解决方案

虽然.NET Core中未实现此功能,但我们可以通过创建自定义JsonConverter来应用所需的顺序。有几种方法可以实现。以下是我提出的实现。

说明-JsonPropertyOrderConverter处理具有至少一个属性且应用了自定义订单值的类型。对于每种类型,它都会创建并缓存一个排序函数,该函数将原始对象转换为具有特定顺序设置的属性的ExpandoObjectExpandoObject保持属性的顺序,因此可以将其传递回JsonSerializer进行进一步的序列化。转换器还考虑应用于序列化属性的JsonPropertyNameAttributeJsonPropertyOrderAttribute属性。

请注意,排序器函数处理PropertyInfo对象,这可能会增加一些额外的延迟。如果性能在您的方案中至关重要,请考虑基于“表达式树”实现Function<object, object>排序器。

class Program
{
    static void Main(string[] args)
    {
        var test = new Test { Bar = 1, Baz = 2, Foo = 3 };

        // Add JsonPropertyOrderConverter to enable ordering
        var opts = new JsonSerializerOptions();
        opts.Converters.Add(new JsonPropertyOrderConverter());

        var serialized = JsonSerializer.Serialize(test, opts);

        // Outputs: {"Bar":1,"Baz":2,"Foo":3}
        Console.WriteLine(serialized);
    }
}

class Test
{
    [JsonPropertyOrder(1)]
    public int Foo { get; set; }

    [JsonPropertyOrder(-1)]
    public int Bar { get; set; }

    // Default order is 0
    public int Baz { get; set; }

}

/// <summary>
/// Sets a custom serialization order for a property.
/// The default value is 0.
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
sealed class JsonPropertyOrderAttribute : Attribute
{
    public int Order { get; }

    public JsonPropertyOrderAttribute(int order)
    {
        Order = order;
    }
}

/// <summary>
/// For Serialization only.
/// Emits properties in the specified order.
/// </summary>
class JsonPropertyOrderConverter : JsonConverter<object>
{
    delegate ExpandoObject SorterFunc(object value, bool ignoreNullValues);

    private static readonly ConcurrentDictionary<Type, SorterFunc> _sorters
        = new ConcurrentDictionary<Type, SorterFunc>();

    public override bool CanConvert(Type typeToConvert)
    {
        // Converter will not run if there is no custom order applied
        var sorter = _sorters.GetOrAdd(typeToConvert, CreateSorter);
        return sorter != null;
    }

    public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotSupportedException();
    }

    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
    {
        // Resolve the sorter.
        // It must exist here (see CanConvert).
        var sorter = _sorters.GetOrAdd(value.GetType(), CreateSorter);

        // Convert value to an ExpandoObject
        // with a certain property order
        var sortedValue = sorter(value, options.IgnoreNullValues);

        // Serialize the ExpandoObject
        JsonSerializer.Serialize(writer, (IDictionary<string, object>)sortedValue, options);
    }

    private SorterFunc CreateSorter(Type type)
    {
        // Get type properties ordered according to JsonPropertyOrder value
        var sortedProperties = type
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(x => x.GetCustomAttribute<JsonIgnoreAttribute>(true) == null)
            .Select(x => new
            {
                Info = x,
                Name = x.GetCustomAttribute<JsonPropertyNameAttribute>(true)?.Name ?? x.Name,
                Order = x.GetCustomAttribute<JsonPropertyOrderAttribute>(true)?.Order ?? 0
            })
            .OrderBy(x => x.Order)
            .ToList();

        // If all properties have the same order,
        // there is no sense in explicit sorting
        if (!sortedProperties.Any(x => x.Order != 0))
        {
            return null;
        }

        // Return a function assigning property values
        // to an ExpandoObject in a specified order
        return new SorterFunc((src, ignoreNullValues) =>
        {
            IDictionary<string, object> dst = new ExpandoObject();

            foreach (var prop in sortedProperties)
            {
                var propValue = prop.Info.GetValue(src);

                if (!ignoreNullValues || !(propValue is null))
                {
                    dst.Add(prop.Name, propValue);
                }
            }

            return (ExpandoObject)dst;
        });
    }
}

JSON Post and Decode数组到PHP - php

我正在尝试使用JSON将数组发布到PHP文件。这没用。问题是什么也没发生。如果我将数据类型分解为:“ json”,则会收到警报(但没有数据)。这是我的jQuery代码var arr = new Array(); arr.push('1','Brussels|25'); arr.push('2',&#…

System.out.printf不打印整数参数 - java

我是Java编程的新手,无法从另一个类返回方法。这两个类都可以编译并成功运行。我可以从一个类中调用一个简单的int,但是当我想计算用户输入的两个输入整数时,我只会得到一个空格。这是我的计算课class calculations { public final int AGE = 53; public int numbers(int num1, int num2…

JAVA:json + websocket - java

我正在与朋友一起编程项目。我们将其分为两部分,我负责客户端(简单的窗口应用程序),他制作了服务器。我应该借助websocket将JSON对象发送到他的服务器(他给了我信息,我应该发送http://pastebin.com/dmYBtN25的信息)。我知道如何创建json对象,但是我的问题是如何将websocket lib与json结合使用(当前我正在使用we…

如何将Jackson的TypeReference与泛型一起使用? - java

对于json映射,我使用以下方法:public static <T> T mapJsonToObject(String json, T dtoClass) throws Exception { ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(json, new T…

使用Java检测用户计算机上是否安装了某些软件 - java

我有一个Java应用程序,它需要某些软件(其中一个是Perl)才能运行。我用来检测Perl的方法是:Runtime.getRuntime().exec("perl Test.pl"); 如果存在IOException,则声明不存在Perl。但是,我的一位用户抱怨该应用程序不断失败,因为他没有将Perl放在其路径变量中。所以这就是为什么我要…