2016-06-19 4 views
0

Я пытаюсь де-сериализовать List<string>, что на самом деле является List<myClass>, объекты которого были сериализованы. Пример:Де-сериализовать JSON-список сериализованных объектов JSON

static void Main(string[] args) 
{ 
    List<MyThirdClass> myThirdClass = new List<MyThirdClass>(new[] { new MyThirdClass { RoleId = 123, RoleName = "123" }, new MyThirdClass { RoleId = 234, RoleName = "234" } }); 
    List<MySecondSerializedClass> mySecondSerializedClass = new List<MySecondSerializedClass>(); 
    foreach (MyThirdClass thirdClass in myThirdClass) 
    { 
     MySecondSerializedClass secondClass = new MySecondSerializedClass { Roles = new List<string>() }; 
     foreach (MyThirdClass tClass in myThirdClass) 
     { 
      secondClass.Roles.Add(JsonConvert.SerializeObject(tClass)); 
     } 
     mySecondSerializedClass.Add(secondClass); 
    } 
    MyFirstSerializedClass firstClass = new MyFirstSerializedClass 
    { 
     Id = 1, 
     Name = "1", 
     Roles = mySecondSerializedClass 
    }; 

    string serializedFirstClass = JsonConvert.SerializeObject(firstClass, Formatting.Indented); 
    MyFirstNonSerializedClass nonSerializedFirstClass = JsonConvert.DeserializeObject<MyFirstNonSerializedClass>(serializedFirstClass); 
} 

public class MyFirstSerializedClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<MySecondSerializedClass> Roles { get; set; } 
} 

public class MyFirstNonSerializedClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<MySecondNonSerializedClass> Roles { get; set; } 
} 

public class MySecondSerializedClass 
{ 
    public List<string> Roles { get; set; } 
} 

public class MySecondNonSerializedClass 
{ 
    public List<MyThirdClass> Roles { get; set; } 
} 

public class MyThirdClass 
{ 
    public int RoleId { get; set; } 
    public string RoleName { get; set; } 
} 

serializedFirstClass возвращает JSON как это:

{ 
    "Id": 1, 
    "Name": "1", 
    "Roles": [ 
    { 
     "Roles": [ 
     "{\"RoleId\":123,\"RoleName\":\"123\"}", 
     "{\"RoleId\":234,\"RoleName\":\"234\"}" 
     ] 
    }, 
    { 
     "Roles": [ 
     "{\"RoleId\":123,\"RoleName\":\"123\"}", 
     "{\"RoleId\":234,\"RoleName\":\"234\"}" 
     ] 
    } 
    ] 
} 

И пытается десериализации она генерирует исключение с сообщением:

Ошибка преобразования значения "{" Идентификатор роли ": 123," RoleName ":" 123 "}", чтобы ввести 'ConsoleApplication1.Program + MyThirdClass'. Путь 'Роли [0] .Roles [0]', строка 7, позиция 47.

Есть ли что-то я делаю неправильно или каким-либо образом рекурсивно-сериализации MyFirstSerializedClass в MyFirstNonSerializedClass?

+0

Почему внешние роли не экранированы, а внутренние? – abatishchev

+0

@abatishchev Я бы предположил, что это потому, что я сериализую роли как строку, а затем повторно сериализую их. –

+0

Объявляет роли в MySecondNonSerializedClass as List abatishchev

ответ

1

Вы можете сделать это с помощью одного набора классов и необязательной JsonConverter для MyThirdClass, который считывает текущий маркер JSON в виде строки буквальной, а затем использует вложенный сериалайзер десериализации, что строковый литерал из JSON в качестве экземпляра MyThirdClass. Добавьте конвертер в JsonSerializerSettings.Converters, если вы хотите сериализовать или десериализовать свой класс как встроенную строку; оставьте это для сериализации в качестве объекта.

Таким образом:

public class MyFirstClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<MySecondClass> Roles { get; set; } 
} 

public class MySecondClass 
{ 
    public List<MyThirdClass> Roles { get; set; } 
} 

public class MyThirdClass 
{ 
    public int RoleId { get; set; } 
    public string RoleName { get; set; } 
} 

public sealed class MyThirdClassStringConverter : JsonConverter 
{ 
    readonly JsonSerializerSettings settings; 

    public MyThirdClassStringConverter() : this(null) { } 

    public MyThirdClassStringConverter(JsonSerializerSettings settings) 
    { 
     this.settings = settings; 
    } 

    JsonSerializer GetInnerSerializer() 
    { 
     var innerSerializer = JsonSerializer.CreateDefault(settings); 
     for (int i = innerSerializer.Converters.Count - 1; i >= 0; i--) 
      if (innerSerializer.Converters[i] is MyThirdClassStringConverter) 
       innerSerializer.Converters.RemoveAt(i); 
     return innerSerializer; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(MyThirdClass).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var innerSerializer = GetInnerSerializer(); 
     if (reader.TokenType == JsonToken.String) 
     { 
      var s = reader.Value.ToString(); 
      using (var innerReader = new StringReader(s)) 
       return innerSerializer.Deserialize(innerReader, objectType); 
     } 
     else 
     { 
      return innerSerializer.Deserialize(reader, objectType); 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var innerSerializer = GetInnerSerializer(); 
     var sb = new StringBuilder(); 
     using (var innerWriter = new StringWriter(sb)) 
      innerSerializer.Serialize(innerWriter, value); 
     writer.WriteValue(sb.ToString()); 
    } 
} 

Затем, используйте его следующим образом:

var stringSettings = new JsonSerializerSettings { Converters = new[] { new MyThirdClassStringConverter() } }; 

// Deserialize JSON where MyThirdClass objects are embedded strings 
var root = JsonConvert.DeserializeObject<MyFirstClass>(stringJson, stringSettings); 

// Re-serialize to JSON where MyThirdClass objects are objects 
var newNonStringJson = JsonConvert.SerializeObject(root, Formatting.Indented); 
// Re-serialize to JSON where MyThirdClass objects are embedded strings 
var newStringJson = JsonConvert.SerializeObject(root, Formatting.Indented, stringSettings); 

Обратите внимание, что преобразователь должен не быть применен к MyThirdClass непосредственно с помощью [JsonConverter(typeof(MyThirdClassStringConverter))], как зацикливание приведет.Метод конвертора проверяет, является ли текущий токен строкой или объектом и соответствующим образом адаптируется, поэтому его можно использовать для десериализации JSON в любом формате.

Пример fiddle.

+0

Принимая ваш ответ, потому что это самый полный ответ, но я пошел другим путем с моими классами, которые не дублируют объекты –

1

Вы ожидаете deserialize string до MyThirdClass Структура, которая невозможна.

Они на самом деле не то же самое.

Список строки будет сериализовать в

" \" SomeProperty \ ": \" SomePropertyValue \»",
" \ "SomeProperty2 \": \ "SomePropertyValue \" "

Хотя Список CustomClass будет

"SomeProperty": "SomePropertyValue",
"SomeProperty2": "SomeProperty2Value"

+0

Итак, как я могу сериализовать его таким образом, что позже смогу его сериализовать? Эта двойная сериализация предназначена для хранения в таблице ATS (Лазерное хранилище таблиц). Некоторый пример кода был бы замечательным –

1

При сериализации преобразовании MyThirdClass в строку. При десериализации вы нуждаетесь в обратном преобразовании. Добавьте неявное преобразование из строки в ваш тип.

public static implicit operator MyThirdClass(string s) 
{ 
    // when serializing indented => 
    // return JsonConvert.DeserializeObject<B3>(s, new JsonSerializerSettings() { Formatting = Formatting.Indented}); 
    // otherwise 
    return JsonConvert.DeserializeObject<B3>(s); 
} 
+0

Спасибо, я закончил удаление сериализованных классов и придерживался другого подхода. –

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