2011-07-28 24 views
5

estoy usando Json.NET Primer vistazo a esto:Serializar XNA rectángulo con 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); 

Todo funciona como se esperaba. La salida de la consola es: "3, 6, 32, 32"

Pero cuando quiero hacer lo mismo con the XNA Rectangle, aparece un error. (Justo sustituido a la antigua utilizando con este "usando Microsoft.Xna.Framework;")

La salida de la consola es: "{X: -3 Y: 6 Anchura: 32 Altura: 32}"

y la el error que arroja es: "Error al convertir el valor" {X: -3 Y: 6 Ancho: 32 Altura: 32} "escribir" Microsoft.Xna.Framework.Rectangle '. "

  1. ¿Por qué ocurre esto?

  2. ¿Qué está mal y cómo soluciono esto?

+0

Intenta construir Json.NET de la fuente por lo puede ver la excepción lanzada en el depurador.La respuesta al n. ° 1: parece bastante claro que está convirtiendo 'Rectangle' utilizando su método' ToString', en lugar de extraer los valores individuales de los miembros, y no hay ningún método para convertirlo. Podría adivinar que Json.NET usa las propiedades públicas get/set (como 'System.Drawing.Rectangle') y que no" ve "' public * fields * de Microsoft.Xna.Framework.Rectangle'. –

Respuesta

5

He hecho algunas averiguaciones, este es el código que provoca la excepción:

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

La llamada real al delegado que hace el trabajo Convert no puede encontrar un convertidor de este tipo. Investigar la causa de esto, ya que el serializador puede serializar y deserializar otros tipos correctamente.

EDIT:

esto no funciona, ya que el tipo de XNA rectángulo se define como:

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

Json.NET recupera tipo TypeConverter, y llama a este método en él:

TypeConverter fromConverter = GetConverter(targetType); 

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

El RectangleConverter tiene una bandera que dice "supportsStringConvert = false", por lo que intenta convertir una cadena en ella.

Esta es la razón por la que la deserialización de este objeto específico está fallando.

+0

¡Guau, trabajo increíble! Gracias por descubrir esto. ¿Tiene alguna idea de cómo resolver el problema o cómo solucionarlo? – riki

+0

Puedes intentar serializarlo en un objeto diferente (no en una cadena) si json.net lo permite. Lo comprobaré mañana –

+0

Parece que tendrá que crear un DTO simple para serializar/deserializar la estructura Rectángulo XNA – MattDavey

2

Descubrí una forma de hacer que Newtonsoft.Json (Json.Net) juegue bien con la clase Rectangle de XNA. En primer lugar, el rectángulo debe ser una propiedad de una clase para que pueda darle un atributo 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; 
    } 
} 

Probablemente podría mejorarse así que la regeneración es apreciado.

0

Esto es, con mucho, la mejor solución que he encontrado para este problema:

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

Y justo configurar Newtonsoft.JSON a utilizar el sistema de resolución

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

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