2014-01-26 3 views
20

У меня есть JsonConverter, что, в зависимости от конкретного флага экземпляра, необходимо либоRun сериализация по умолчанию логика от JsonConverter

  • запуска пользовательской логики сериализации
  • запустить Json.NET сериализации логика по умолчанию

Как можно использовать стандартную логику сериализации Json.NET от JsonConverter?

Thanks

+0

возможно дубликат [рекурсивный вызов JsonSerializer в JsonConverter] (http://stackoverflow.com/questions/16085805/recursively-call-jsonserializer-in-a-jsonconverter) –

ответ

9

Вот пример. Предположим, что ваш класс сериализовать выглядит так:

class Foo 
{ 
    public bool IsSpecial { get; set; } 
    public string A { get; set; } 
    public string B { get; set; } 
    public string C { get; set; } 
} 

Флаг IsSpecial используется для управления, делают ли мы что-то особенное в конвертере или просто позволить вещи сериализации естественно. Вы можете написать свой конвертер, как это:

class FooConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(Foo).IsAssignableFrom(objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     Foo foo = (Foo)value; 
     JObject jo; 
     if (foo.IsSpecial) 
     { 
      // special serialization logic based on instance-specific flag 
      jo = new JObject(); 
      jo.Add("names", string.Join(", ", new string[] { foo.A, foo.B, foo.C })); 
     } 
     else 
     { 
      // normal serialization 
      jo = JObject.FromObject(foo); 
     } 
     jo.WriteTo(writer); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Затем, чтобы использовать конвертер, передать экземпляр этого к SerializeObject метода (например, в настройках). (НЕ украшаю целевой класс с атрибутом JsonConverter, или это приведет к бесконечной рекурсии при сериализации.)

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<Foo> foos = new List<Foo> 
     { 
      new Foo 
      { 
       A = "Moe", 
       B = "Larry", 
       C = "Curly", 
       IsSpecial = false 
      }, 
      new Foo 
      { 
       A = "Huey", 
       B = "Dewey", 
       C = "Louie", 
       IsSpecial = true 
      }, 
     }; 

     JsonSerializerSettings settings = new JsonSerializerSettings(); 
     settings.Converters.Add(new FooConverter()); 
     settings.Formatting = Formatting.Indented; 

     string json = JsonConvert.SerializeObject(foos, settings); 
     Console.WriteLine(json); 
    } 
} 

Выход:

[ 
    { 
    "IsSpecial": false, 
    "A": "Moe", 
    "B": "Larry", 
    "C": "Curly" 
    }, 
    { 
    "names": "Huey, Dewey, Louie" 
    } 
] 
+0

Это работает хорошо, за исключением того, что я имеют пользовательские преобразователи, которые необходимо включить в «нормальный» процесс сериализации. Поэтому для этого примера «FooConverter» также необходимо включить в процесс сериализации. Это приводит к тому, что «нормальная» сериализация снова проходит через «FooConverter», с «IsSpecial = false». Иными словами, проблема заключалась в сериализации поля, встречающегося во время сериализации, иначе, чем объект, переданный непосредственно в 'JsonConvert.Serialize'. A (неоптимальное) решение требует, чтобы все ссылки на поля были аннотированы ссылкой '[JsonConverter]. – sient

+0

Я думаю, что, возможно, неправильно понял ваш вопрос. Можете ли вы изменить свой вопрос, включив простой пример (Foo, Bar и т. Д.) Иерархии классов, которую вы пытаетесь сериализовать, и каков ваш желаемый выход JSON, если ваш конвертер работал так, как вам хотелось? Похоже, вы хотите, чтобы он вел себя по-разному в зависимости от того, является ли объект, который будет сериализован, на корневом уровне или нет, в отличие от того, что он управляется флагом на экземплярах объекта. –

+1

Это работает ужасно, пока вы не пытаетесь сохранить ссылки. Однако он не работает, если вам нужно поле id. –

-1

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

class FooConverter : JsonConverter 
{ 
    bool _canWrite = true; 
    public override bool CanWrite 
    { 
     get { return _canWrite;} 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     Foo foo = (Foo)value; 
     JObject jo; 
     if (foo.IsSpecial) 
     { 
      // special serialization logic based on instance-specific flag 
      jo = new JObject(); 
      jo.Add("names", string.Join(", ", new string[] { foo.A, foo.B, foo.C })); 
     } 
     else 
     { 
      // normal serialization 
      _canWrite = false; 
      jo = JObject.FromObject(foo); 
      _canWrite = true; 
     } 
     jo.WriteTo(writer); 
    } 
} 
+3

Это не потокобезопасность. –

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