序列化时子元素的 Newtonsoft 内联格式

时间:2023-04-26
本文介绍了序列化时子元素的 Newtonsoft 内联格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

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

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

<代码>{名称":xxx",描述":xxx",subelem":[{"val1": 1, "val2": 2, ...},//inline,{"val1": 1, "val2": 2, ...},...]subelem2":{val1":1,val2":2,...}}

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

解决方案

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

公共类 NoFormattingConverter : JsonConverter{[线程静态]静态布尔不能写;//以线程安全的方式禁用转换器.bool 不能写 { 得到 { 返回不能写;} 设置 { 不能写 = 值;} }公共覆盖 bool CanWrite { get { return !CannotWrite;} }公共覆盖 bool CanRead { get { return false;} }公共覆盖 bool CanConvert(Type objectType){抛出新的 NotImplementedException();//应该作为属性应用,而不是包含在 JsonSerializerSettings.Converters 列表中.}public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){抛出新的 NotImplementedException();}public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer){使用 (new PushValue<bool>(true, () => CannotWrite, val => CannotWrite = val))使用 (new PushValue(Formatting.None, () => writer.Formatting, val => writer.Formatting = val)){序列化器.序列化(作家,价值);}}}公共结构 PushValue<T>: IDisposable{行动<T>设定值;旧值;public PushValue(T value, FuncgetValue, ActionsetValue){if (getValue == null || setValue == null)抛出新的 ArgumentNullException();this.setValue = setValue;this.oldValue = getValue();设置值(值);}#region IDisposable 成员//通过使用一次性结构,我们避免了分配和释放可终结类实例的开销.公共无效处置(){如果(设置值!= null)设置值(旧值);}#endregion}

然后像这样将它应用到一个类(或属性)上:

[JsonConverter(typeof(NoFormattingConverter))]公共类 NestedClass{公共字符串 [] 值 { 获取;放;}}公共类TestClass{公共字符串 AValue { 获取;放;}公共 NestedClass NestedClass { 获取;放;}公共字符串 ZValue { 获取;放;}公共静态无效测试(){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": "一个值","NestedClass":{"Values":["one","two","three"]},Z 值":Z 值"}

Is it possible to create an attribute to serialize some subelements inline (Formatting.None) with newtonsoft json.net?

I have a very huge set of data and I want to keep it readeable. Some subelements are not very important and can be writen inline.

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

I want to force the inline serialization for some sub objects of my models. In this case, "subelem" items will be written inline. Thanks

解决方案

Adding the converter as a JsonConverterAttribute on a class is trickier because the simplest implementation will lead to an infinite recursion as the converter calls itself. Thus it's necessary to disable the converter for recursive calls in a thread-safe manner, like so:

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
}

And then apply it to a class (or property) like so:

[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));
    }
}

The output of the Test() method above is:

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

这篇关于序列化时子元素的 Newtonsoft 内联格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:如何从 JSON 字符串中获取深度嵌套的属性? 下一篇:JsonConvert.DeserializeObject&lt;&gt;(string) 为 $id

相关文章