2014-02-21 2 views
1

У меня есть класс, который требует сериализации/десериализации. Это выглядит следующим образом:Как мне (де) сериализовать список типа, который требует пользовательский JsonConverter?

public class Animation 
{ 
    [JsonProperty] 
    private readonly string name; 

    [JsonProperty] 
    private readonly IList<Rectangle> frames; 
} 

Однако Json.Net не играет хорошо с Rectangle класса XNA в. Он нуждается в обычном JsonConverter, который я managed to scrape together. Это отлично работает на классах с одной Rectangle собственности, как:

public class Sprite 
{ 
    [JsonConverter(typeof(RectangleConverter))] 
    [JsonProperty] 
    private readonly Rectangle frame; 
} 

Но как я применить этот конвертер к списку Rectangle с в моем Animation классе?

+0

возможно дубликат [Как реализовать пользовательские JsonConverter в Json.NET десериализации списка объектов базового класса] (http://stackoverflow.com/questions/8030538/how-to-implement-custom-jsonconverter-in-json-net-to-deserialize-a-list-of-base) –

+0

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

ответ

1

В соответствии с the doc структура XNA Rectangle обозначена как имеющая TypeConverter, а также по умолчанию преобразователи типа always return true when asked to convert to string. Из-за этого Json.Net по умолчанию попытается создать контракт на строку вместо договора объекта, что приведет к ошибке при использовании с вашим RectangleConverter. Это можно исправить с помощью настраиваемого ContractResolver, чтобы сообщить Json.Net, что Rectangle следует рассматривать как объект, а не строку. Мы также можем установить преобразователь внутри резольвера, поэтому вам не нужно украшать ваши свойства класса атрибутом [JsonConverter], где бы вы ни использовали Rectangle.

Вот код, вам потребуется:

class CustomResolver : DefaultContractResolver 
{ 
    protected override JsonContract CreateContract(Type objectType) 
    { 
     if (objectType == typeof(Rectangle) || objectType == typeof(Rectangle?)) 
     { 
      JsonContract contract = base.CreateObjectContract(objectType); 
      contract.Converter = new RectangleConverter(); 
      return contract; 
     } 
     return base.CreateContract(objectType); 
    } 
} 

Чтобы использовать распознаватель, добавьте его в настройках Serializer и передать в DeserializeObject() или SerializeObject(), как это:

JsonSerializerSettings settings = new JsonSerializerSettings(); 
settings.ContractResolver = new CustomResolver(); 

Animation anim = JsonConvert.DeserializeObject<Animation>(json, settings); 
+0

Можете ли вы разместить свой JSON? –

+0

{"name": "moveleft", "frames": [{"x": 0, "y": 128, "width": 64, "height": 64}, {"x": 128, "y ": 128," width ": 64," height ": 64}]} –

+0

Это определенно проблема с« Rectangle »XNA - см. Ссылку, включенную в мой оригинальный пост. –

1

Надеюсь, кто-то приходит (это должно быть одно), но сейчас это работает на меня:

public class RectangleListConverter : RectangleConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var rectangleList = (IList<Rectangle>)value; 

     var jArray = new JArray(); 

     foreach (var rectangle in rectangleList) 
     { 
      jArray.Add(GetObject(rectangle)); 
     } 

     jArray.WriteTo(writer); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var rectangleList = new List<Rectangle>(); 

     var jArray = JArray.Load(reader); 

     foreach (var jToken in jArray) 
     { 
      rectangleList.Add(GetRectangle(jToken)); 
     } 

     return rectangleList; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     throw new NotImplementedException(); 
    } 
} 

мне пришлось изменить RectangleConverter я использую: класс

public class RectangleConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var rectangle = (Rectangle)value; 

     var jObject = GetObject(rectangle); 

     jObject.WriteTo(writer); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var jObject = JObject.Load(reader); 

     return GetRectangle(jObject); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     throw new NotImplementedException(); 
    } 

    protected static JObject GetObject(Rectangle rectangle) 
    { 
     var x = rectangle.X; 
     var y = rectangle.Y; 
     var width = rectangle.Width; 
     var height = rectangle.Height; 

     return JObject.FromObject(new { x, y, width, height }); 
    } 

    protected static Rectangle GetRectangle(JObject jObject) 
    { 
     var x = GetTokenValue(jObject, "x") ?? 0; 
     var y = GetTokenValue(jObject, "y") ?? 0; 
     var width = GetTokenValue(jObject, "width") ?? 0; 
     var height = GetTokenValue(jObject, "height") ?? 0; 

     return new Rectangle(x, y, width, height); 
    } 

    protected static Rectangle GetRectangle(JToken jToken) 
    { 
     var jObject = JObject.FromObject(jToken); 

     return GetRectangle(jObject); 
    } 

    protected static int? GetTokenValue(JObject jObject, string tokenName) 
    { 
     JToken jToken; 
     return jObject.TryGetValue(tokenName, StringComparison.InvariantCultureIgnoreCase, out jToken) ? (int)jToken : (int?)null; 
    } 
} 

Анимация с новым JsonConverter атрибутом:

public class Animation 
{ 
    [JsonProperty] 
    private readonly string name; 

    [JsonConverter(typeof(RectangleListConverter))] 
    [JsonProperty] 
    private readonly IList<Rectangle> frames; 
} 
Смежные вопросы