2011-07-28 83 views
5

我使用Json.NET 在此首先看序列化XNA矩形:與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」

但是當我想用the XNA Rectangle做同樣的事情時,出現錯誤。 (只是與此使用代替了舊的 「使用Microsoft.Xna.Framework;」)

控制檯輸出是: 「{X:-3 Y:6寬度:32身高:32}」

和它引發的錯誤是:「錯誤轉換值」{X:-3 Y:6 Width:32 Height:32}「鍵入'Microsoft.Xna.Framework.Rectangle'」。

  1. 爲什麼會發生這種情況?

  2. 怎麼回事,我該如何解決這個問題?

+0

嘗試從源,以便建立Json.NET您可以查看在調試器正在拋出的異常。對#1的回答:似乎很清楚,它使用其「ToString」方法轉換「Rectangle」,而不是提取各個成員值,並且沒有方法將其轉換回來。我可能會猜測Json.NET使用public get/set屬性(如'System.Drawing.Rectangle'),並且不會「看到」Microsoft.Xna.Framework.Rectangle的public * fields *。 –

回答

5

我已經做了一些檢查,這是導致異常的代碼:

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矩形類型定義爲:

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

Json.NET檢索類型轉換器類型,並呼籲它這個方法:

TypeConverter fromConverter = GetConverter(targetType); 

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

的RectangleConverter有一個標誌說:「supportsStringConvert =假」,因此試圖進入它無法將字符串轉換。

這是反序列化這一特定對象失敗的原因。

+0

哇,真棒!感謝您的發現。 你有任何想法如何解決這個問題,或者如何解決它? – riki

+0

如果json.net允許,您可以嘗試將其序列化爲不同的對象(不是字符串)。我將在明天看到它 –

+0

看起來您需要創建一個簡單的DTO來序列化/反序列化XNA Rectangle結構 – MattDavey

2

我想出了一個辦法讓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

這是迄今爲止我已經找到了這一問題的最佳解決方案:

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