Sérialiser le Rectangle XNA avec Json.NET

j'utilise Json.NET Regardez d'abord ceci:

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

Tout fonctionne comme prévu. La sortie de la console est: "3, 6, 32, 32"

mais quand je veux faire la même chose avec le Rectangle XNA , je reçois une erreur. (vient de remplacer l'ancien en utilisant avec ce "en utilisant Microsoft.Xna.Framework;")

la sortie de la console est: "{X:-3 Y:6 Largeur:32 Hauteur: 32}"

et l'erreur, il lance: "Erreur lors de la conversion de la valeur "{X:-3 Y:6 Largeur:32 Hauteur:32}" type " de Microsoft.Xna.Framework.Rectangle"."

  1. pourquoi cela se produit-il?

  2. Qu'est-ce qui ne va pas, et comment je répare ça??

5
demandé sur svick 2011-07-28 09:25:59

3 réponses

j'ai vérifié, c'est le code qui cause l'exception:

    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);
    }

l'appel réel au délégué qui fait le travail de conversion ne peut pas trouver un convertisseur pour ce type. En étudiant la cause de cela, car le serializer est capable de sérialiser et de deserialiser d'autres types correctement.

EDIT:

cela ne fonctionne pas, puisque le type Rectangle XNA est défini comme:

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

Json.NET récupère le type TypeConverter, et appelle cette méthode sur elle:

  TypeConverter fromConverter = GetConverter(targetType);

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

le RectangleConverter a un drapeau disant" supportsStringConvert = false", donc tenter de convertir une chaîne en elle échoue.

c'est la raison pour laquelle la desérialisation de cet objet spécifique est un échec.

5
répondu lysergic-acid 2011-07-28 22:20:44

j'ai trouvé un moyen d'obtenir Newtonsoft.Json (Json.Net) pour jouer gentil avec XNA Rectangle de la classe. Tout d'abord, votre rectangle doit être une propriété d'une classe pour que vous puissiez lui donner un attribut 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;
    }
}

il pourrait probablement être amélioré de sorte que la rétroaction est appréciée.

2
répondu David Kennedy 2014-01-26 04:41:34

C'est de loin la meilleure solution que j'ai trouvé pour ce problème:

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);
  }
}

et il suffit de configurer Newtonsoft.JSON pour utiliser le résolveur

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

var rect = JsonConvert.DeserializeObject<Rectangle>(jsonData, settings);
0
répondu Elliott Darfink 2017-05-29 08:54:25