序列化时子元素的牛顿软件内联格式

本文关键字:软件 格式 元素 序列化 | 更新日期: 2023-09-27 17:56:02

是否可以创建一个属性来使用 newtonsoft json.net 内联序列化某些子元素(Formatting.None)?

我有一组非常庞大的数据,我想保持它的可读性。有些子元素不是很重要,可以内联编写。

{
    "name": "xxx",
    "desc": "xxx",
    "subelem": [
        {"val1": 1, "val2": 2, ...}, //inline,
        {"val1": 1, "val2": 2, ...},
        ...
    ]
    "subelem2": {
        "val1": 1,
        "val2": 2,
        ...
    }
}

我想对模型的某些子对象强制内联序列化。在这种情况下,"subelem"项目将被内联写入。谢谢

序列化时子元素的牛顿软件内联格式

将转换器添加为类上的JsonConverterAttribute更棘手,因为最简单的实现将导致转换器调用自身的无限递归。 因此,有必要以线程安全的方式禁用递归调用的转换器,如下所示:

public class NoFormattingConverter : JsonConverter
{
    [ThreadStatic]
    static bool cannotWrite;
    // Disables the converter in a thread-safe manner.
    bool CannotWrite { get { return cannotWrite; } set { cannotWrite = value; } }
    public override bool CanWrite { get { return !CannotWrite; } }
    public override bool CanRead { get { return false; } }
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException(); // Should be applied as a property rather than included in the JsonSerializerSettings.Converters list.
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        using (new PushValue<bool>(true, () => CannotWrite, val => CannotWrite = val))
        using (new PushValue<Formatting>(Formatting.None, () => writer.Formatting, val => writer.Formatting = val))
        {
            serializer.Serialize(writer, value);
        }
    }
}
public struct PushValue<T> : IDisposable
{
    Action<T> setValue;
    T oldValue;
    public PushValue(T value, Func<T> getValue, Action<T> setValue)
    {
        if (getValue == null || setValue == null)
            throw new ArgumentNullException();
        this.setValue = setValue;
        this.oldValue = getValue();
        setValue(value);
    }
    #region IDisposable Members
    // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
    public void Dispose()
    {
        if (setValue != null)
            setValue(oldValue);
    }
    #endregion
}

然后将其应用于类(或属性),如下所示:

[JsonConverter(typeof(NoFormattingConverter))]
public class NestedClass
{
    public string[] Values { get; set; }
}
public class TestClass
{
    public string AValue { get; set; }
    public NestedClass NestedClass { get; set; }
    public string ZValue { get; set; }
    public static void Test()
    {
        var test = new TestClass { AValue = "A Value", NestedClass = new NestedClass { Values = new[] { "one", "two", "three" } }, ZValue = "Z Value" };
        Debug.WriteLine(JsonConvert.SerializeObject(test, Formatting.Indented));
    }
}

上述Test()方法的输出为:

{
  "AValue": "A Value",
  "NestedClass":{"Values":["one","two","three"]},
  "ZValue": "Z Value"
}