2015-01-26 3 views
1

Я знаю, что Json.NET поддерживает условные сериализации с помощью ShouldSerialize{PropName}Json.NET условной сериализация для всего типа

Но есть ли способ предотвратить целый тип сериализовать без изменения типа, который ссылается на это? , например.

public class Foo 
{ 
    public bool Enabled {get;set;} 
    ...other properties 
} 

public class Bar 
{ 
    public Foo SomeFoo {get;set;} 
    public Foo OtherFoo {get;set;} 
} 

Я хочу Bar типа, чтобы не включать SomeFooo или OtherFoo в зависимости от того, если включено свойство установлено. если SomeFoo.Enabled = false, то Bar.SomeFoo не следует сериализовать.

Так что я хочу условную сериализацию для ссылочного свойства. И я не хочу, чтобы потребление типа Foo имело дополнительный код или атрибуты. все должно идти по типу Foo.

Я мог бы добавить ShouldSerializeSomeFoo в баре .. но это не то, что я ищу ..

ответ

2

Вы можете написать пользовательский JsonConverter для обработки сериализации Foo.

Я написал очень базовую версию ниже, я бы предложил изучить ее немного глубже.

Эта версия сохраняет ссылку на свойство, просто не сериализует объект. Вы также можете написать конвертер для Bar, который игнорирует всю собственность.

public class FooJsonConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var foo = value as Foo; 
     if (foo == null || !foo.Enabled) 
      return; 

     writer.WriteStartObject(); 

     writer.WritePropertyName("Enabled"); 
     serializer.Serialize(writer, foo.Enabled); 

     //Write the rest of the serialization 

     writer.WriteEndObject(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return serializer.Deserialize(reader, objectType); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof (Foo); 
    } 
} 

Использование:

var trueFoo = new Foo() 
{ 
    Enabled = true 
}; 

var falseFoo = new Foo() 
{ 
    Enabled = false 
}; 

var bar = new Bar() 
{ 
    SomeFoo = trueFoo, 
    OtherFoo = falseFoo 
}; 


//{"SomeFoo":{"Enabled":true},"OtherFoo":null} 
var json = JsonConvert.SerializeObject(bar, new FooJsonConverter()); 
2

Я думаю, что лучшим решением этой проблемы является написание пользовательских IContractResolver. Резольер может применять программный код ShouldSerialize к каждому объекту, содержащему Foo, который, в свою очередь, проверяет экземпляр Foo, чтобы убедиться, что он включен. Если это не так, то это свойство вообще не будет сериализовано.

Самый простой способ создать резольвер - получить его от DefaultContractResolver, а затем переопределить метод CreateProperties. Вот код, вам потребуется:

using System; 
using System.Collections.Generic; 
using System.Reflection; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization; 

class CustomResolver : DefaultContractResolver 
{ 
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization); 
     foreach (JsonProperty prop in properties) 
     { 
      if (prop.PropertyType == typeof(Foo)) 
      { 
       prop.ShouldSerialize = obj => 
       { 
        Foo foo = (Foo)type.GetProperty(prop.PropertyName).GetValue(obj); 
        return foo != null && foo.Enabled; 
       }; 
      } 
     } 
     return properties; 
    } 
} 

Вы можете применить пользовательский распознаватель через JsonSerializerSettings так:

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    ContractResolver = new CustomResolver(), 
}; 
string json = JsonConvert.SerializeObject(objToSerialize, settings); 

Вот скрипка с полным демо: https://dotnetfiddle.net/wnLbyD

Смежные вопросы