2015-06-14 43 views
2

是否可以使用newtonsoft json.net創建一個屬性來將某些子元素內聯(Formatting.None)序列化?串行化時子元素的Newtonsoft內聯格式化

我有一個非常龐大的數據集,我想保持readeable。 一些子元素不是很重要,可以內聯書寫。

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

我想強制我的模型的一些子對象的內聯序列化。 在這種情況下,「subelem」項目將被內聯寫入。 謝謝

+0

我問這是前一段時間同樣的問題,取得了良好的回答:https://stackoverflow.com/questions/28655996/how-to-apply-indenting-serialization-only-to-some-properties – Wormbo

+0

擴展鏈接的答案,如果你想縮進純粹基於深度,你可以從['JsonWriter.Top']獲得(http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonWriter_Top.htm)(雖然它是受保護的,所以您可能需要子類JsonTextWriter並創建一個公共方法) – dbc

+0

不幸的是,這不是基於我目前案件的深度,但我有另一個案例,將適合您的答案,謝謝 我會嘗試使用自定義轉換器。 你知道是否可以使用自定義轉換器的自定義屬性? 我會有很多不同的對象需要這個,那麼如果我可以爲每個不同的對象創建一個自定義屬性而不是轉換器,那就太好了。 無論如何,我可以使用你的解決方案。 – Demonia

回答

3

在類上添加轉換器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" 
} 
+1

這正是我需要的。非常感謝你! 我試圖做出類似的東西,但我確實遇到了你提到的問題。 – Demonia