Сериализация прямоугольника XNA с помощью Json.NET - PullRequest
5 голосов
/ 28 июля 2011

Я использую Json.NET Сначала посмотрите на это:

using System.Drawing;
string json = JsonConvert.SerializeObject(new Rectangle(-3,6,32,32), Formatting.Indented);
Console.WriteLine(json);
Rectangle deserializedRectangle = JsonConvert.DeserializeObject<Rectangle>(json);

Все работает как положено.Вывод консоли: «3, 6, 32, 32»

Но когда я хочу сделать то же самое с Прямоугольник XNA , я получаю ошибку.(просто заменил старое использование на «используя Microsoft.Xna.Framework;»)

Вывод на консоль: «{X: -3 Y: 6 Ширина: 32 Высота: 32}»

и выдаваемая ошибка: «Ошибка преобразования значения» {X: -3 Y: 6 Ширина: 32 Высота: 32} »для ввода« Microsoft.Xna.Framework.Rectangle '. "

  1. Почему это происходит?

  2. Что не так, и как я могу это исправить ??

Ответы [ 3 ]

5 голосов
/ 28 июля 2011

Я сделал некоторую проверку, вот код, который вызывает исключение:

    public static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object convertedValue)
    {
      return MiscellaneousUtils.TryAction<object>(delegate { return Convert(initialValue, culture, targetType); }, out convertedValue);
    }

Фактический вызов делегата, который выполняет преобразование, не может найти преобразователь для этого типа.Расследование причины этого, поскольку сериализатор может правильно сериализовать и десериализовать другие типы.

РЕДАКТИРОВАТЬ:

Это не работает, так как тип XNA Rectangle определен как:

    [Serializable]
    [TypeConverter(typeof(RectangleConverter))]
    public struct Rectangle : IEquatable<Rectangle>

Json.NET извлекает тип TypeConverter и вызывает для него этот метод:

  TypeConverter fromConverter = GetConverter(targetType);

  if (fromConverter != null && fromConverter.CanConvertFrom(initialType)) 
  {
       // deserialize
  }

У RectangleConverter есть флаг, говорящий "SupportStringConvert = false", поэтому попытка преобразовать строку в него не удалась.

Это причина того, что десериализация этого конкретного объекта не удалась.

2 голосов
/ 26 января 2014

Я нашел способ заставить Newtonsoft.Json (Json.Net) хорошо играть с классом XNA Rectangle. Во-первых, ваш прямоугольник должен быть свойством класса, чтобы вы могли присвоить ему атрибут JsonConverter:

public class Sprite
{
    [JsonConverter(typeof(MyRectangleConverter))]
    public Rectangle Rectangle;
}

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

        var x = rectangle.X;
        var y = rectangle.Y;
        var width = rectangle.Width;
        var height = rectangle.Height;

        var o = JObject.FromObject( new { x, y, width, height } );

        o.WriteTo( writer );
    }

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

        var x = GetTokenValue( o, "x" ) ?? 0;
        var y = GetTokenValue( o, "y" ) ?? 0;
        var width = GetTokenValue( o, "width" ) ?? 0;
        var height = GetTokenValue( o, "height" ) ?? 0;

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

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

    private static int? GetTokenValue( JObject o, string tokenName )
    {
        JToken t;
        return o.TryGetValue( tokenName, StringComparison.InvariantCultureIgnoreCase, out t ) ? (int)t : (int?)null;
    }
}

Возможно, это можно улучшить, поэтому обратная связь приветствуется.

0 голосов
/ 29 мая 2017

На данный момент это лучшее решение, которое я нашел для этой проблемы:

private class XnaFriendlyResolver : DefaultContractResolver {
  protected override JsonContract CreateContract(Type objectType) {
    // Add additional types here such as Vector2/3 etc.
    if (objectType == typeof(Rectangle)) {
      return CreateObjectContract(objectType);
    }

    return base.CreateContract(objectType);
  }
}

И просто настройте Newtonsoft.JSON для использования распознавателя

var settings = new JsonSerializerSettings() {
  ContractResolver = new XnaFriendlyResolver(),
};

var rect = JsonConvert.DeserializeObject<Rectangle>(jsonData, settings);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...