Serializing XNA Rectangle with Json.NET

允我心安 提交于 2019-12-18 06:26:10

问题


I'm using Json.NET First look at this:

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

Everything works as expected. The console output is: "3, 6, 32, 32"

But when I want to do the same thing with the XNA Rectangle, I get an error. (just replaced the old using with this "using Microsoft.Xna.Framework;")

The console output is: "{X:-3 Y:6 Width:32 Height:32}"

and the error it throws is: "Error converting value "{X:-3 Y:6 Width:32 Height:32}" to type 'Microsoft.Xna.Framework.Rectangle'."

  1. Why is this happening?

  2. Whats going wrong, and how do I fix this??


回答1:


I've done some checking, this is the code that causes the 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);
    }

The actual call to the delegate that does the Convert work cannot find a convertor for this type. Investigating the cause for this, as the serializer is able to serialize and deserialize other types correctly.

EDIT:

This does not work, since the XNA Rectangle type is defined as:

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

Json.NET retrieves TypeConverter type, and calls this method on it:

  TypeConverter fromConverter = GetConverter(targetType);

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

The RectangleConverter has a flag saying "supportsStringConvert = false", so attempting to convert a string into it fails.

This is the reason that deserializing this specific object is failing.




回答2:


I figured out a way to get Newtonsoft.Json (Json.Net) to play nice with XNA's Rectangle class. First, your rectangle should be a property of a class so you can give it a JsonConverter attribute:

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

It could probably be improved so feedback is appreciated.




回答3:


This is by far the best solution I've found for this issue:

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

And just configure Newtonsoft.JSON to use the resolver

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

var rect = JsonConvert.DeserializeObject<Rectangle>(jsonData, settings);


来源:https://stackoverflow.com/questions/6854461/serializing-xna-rectangle-with-json-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!