2016-01-07 3 views
3

Согласно Json.Net documentation все типы IEnumerable должны быть сериализованы как массив json.Сериализация Json.Net IEnumerable с типомNameHandling = авто

Поэтому я ожидаю следующий класс:

public class MyClass 
{ 
    public IEnumerable<string> Values { get; set; } 
} 

сериализовать как:

{ 
    "Values": [] 
} 

Проблема заключается в том, что, когда я использую TypeNameHandling=Auto я получаю:

{ 
    "Values": { 
     "$type": "System.String[], mscorlib", 
     "$values": [] 
    } 
} 

мне нужно TypeNameHandling=Auto для других объектов, но я ожидаю, что IEnumerable использовать defa сверхсериализация. Другие типы (например, IList) работают должным образом.

Это ошибка или я чего-то не хватает?

Здесь полный код, чтобы воспроизвести проблему:

[Test] 
    public void Newtonsoft_serialize_list_and_enumerable() 
    { 
     var target = new Newtonsoft.Json.JsonSerializer 
     { 
      TypeNameHandling = TypeNameHandling.Auto 
     }; 

     var myEvent = new MyClass 
     { 
      Values = new string[0] 
     }; 

     var builder = new StringWriter(); 
     target.Serialize(builder, myEvent); 
     var json = JObject.Parse(builder.ToString()); 

     Assert.AreEqual(JTokenType.Array, json["Values"].Type); 
    } 

    public class MyClass 
    { 
     public IEnumerable<string> Values { get; set; } 
    } 

Я использую Newtonsoft 7.0.1.

UPDATE: Вот еще один тест с использованием нескольких типов:

[Test] 
    public void Newtonsoft_serialize_list_and_enumerable() 
    { 
     var target = new Newtonsoft.Json.JsonSerializer 
     { 
      TypeNameHandling = TypeNameHandling.Auto 
     }; 

     var myEvent = new MyClass 
     { 
      Values1 = new string[0], 
      Values2 = new List<string>(), 
      Values3 = new string[0], 
      Values4 = new List<string>(), 
      Values5 = new string[0] 
     }; 

     var builder = new StringWriter(); 
     target.Serialize(builder, myEvent); 
     var json = builder.ToString(); 
    } 

    public class MyClass 
    { 
     public IEnumerable<string> Values1 { get; set; } 
     public IEnumerable<string> Values2 { get; set; } 
     public IList<string> Values3 { get; set; } 
     public IList<string> Values4 { get; set; } 
     public string[] Values5 { get; set; } 
    } 

И это результаты:

{ 
    "Values1": { 
     "$type": "System.String[], mscorlib", 
     "$values": [] 
    }, 
    "Values2": [], 
    "Values3": { 
     "$type": "System.String[], mscorlib", 
     "$values": [] 
    }, 
    "Values4": [], 
    "Values5": [] 
} 

Опять я не понимаю, почему я получаю разные результаты в зависимости от сочетание.

ответ

3

Автоматическое поведение Json.Net по умолчанию при десериализации в поле или IList заключается в создании экземпляра List. Если вы назначаете экземпляр Array, то единственный способ восстановить его исходное состояние для Json.Net - добавить метаданные $type, что и есть то, что вы видите. т. Е. Существует множество способов десериализации в поле IEnumerable.

С помощью List<string> экземпляра:

var myEvent = new MyClass 
{ 
    Values = new List<string>(), 
}; 

с:

public class MyClass 
{ 
    public IEnumerable<string> Values { get; set; } 
}  

приводит (при сериализованная):

{"Values":["hello"]} 

Кроме того, если вы используете явный constructable тип или используйте список по умолчанию, тогда Json.Net будет использовать это и пропустить $type;

Например:

string[] Values { get; set; } = new string[0]; // not needed 
IEnumerable<string> Values { get; set; } = new string[0]; //$type needed 
IEnumerable<string> Values { get; set; } = new Stack<string>(); //$type needed 
IEnumerable<string> Values { get; set; } = new List<string>; // not needed 
List<string> Values { get; set; } = new List<string>; // not needed 

ObservableCollection<string> Values { get; set; } = 
    new ObservableCollection<string>(); // not needed 
+0

Спасибо, я, вероятно, воспользуюсь этим решением. Но я думаю, что это ошибка, потому что поведение должно быть одинаковым для всех типов, вместо этого я получаю разные результаты в зависимости от того, использую ли я 'List' или' array'. –

+0

Для меня это неверно. Если вы установите 'new string [0]' в поле 'IList', вы получите такое же поведение. Как я уже указывал, поведение десериализации по умолчанию заключается в создании экземпляра 'List' для полей интерфейса Enumerable и' IList'. Если вы укажете явный тип объекта, он будет использовать это вместо этого; но существует множество способов создания экземпляра 'IEnumerable'. единственный способ узнать, какой именно экземпляр вы использовали, если вы идете против значения по умолчанию, заключается в добавлении метаданных '$ type' –

1

Это не ошибка, но это ожидаемое поведение. Вы устанавливаете TypeNameHandling глобально.Вместо того, чтобы глобально установки имени типа обработки можно пометить свойства с атрибутом, как показано ниже, чтобы избежать их включения для установки TypeNameHandling.Auto:

[JsonProperty(TypeNameHandling = TypeNameHandling.None)] 

Вот пример:

public class MyClass 
    { 
     // Indicate the property not to apply any type handling 
     [JsonProperty(TypeNameHandling=TypeNameHandling.None)] 
     public IList<string> Values { get; set; } 

     public string Name { get; set; } 
    } 

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

+0

Обычно мне не нравится вставлять атрибуты сериализации в мой код, но в конечном итоге это может быть хорошее решение. Но я не понимаю, почему для других типов поведение отличается. Например, если объявить свойство как IList и установить его в список . Я думаю, что это ошибка ... –

+0

Это поведение для правильной десериализации производных типов. Когда вы объявляете его глобальным, оно применяется ко всем свойствам. Вот почему поддержка TypeNameHandling предоставляется как атрибуты свойства. Это можно сделать так же, как, например, Отметьте свойства, которые требуют специального TypeHandling для Auto и вообще не используют глобальную настройку. – vendettamit

+0

Да, я понимаю, но почему у Илиста другое поведение? И документация, похоже, подтверждает мои ожидания. –

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