反序列化由不同Json.Net lib生成的Json数据

时间:2012-04-17 22:20:18

标签: c# windows-phone-7 xna json.net

使用Json.Net,你可以反序列化在不同的Json.Net库中生成的Json数据(我使用的是Json.Net的.Net4和windows phone libs)吗?这就是我到目前为止所做的:

我在XNA(.Net 4)中创建了一个Map Editor,它可以使用Json.Net(用于.Net)序列化和反序列化Json数据。我创建了一个结构来存储数据并指定我想要进行serizalized的数据属性,如下所示:

[JsonObject(MemberSerialization.OptIn)]
public struct LevelData
{
    [JsonProperty(PropertyName = "RowCount")]
    private int RowCount;

    [JsonProperty(PropertyName = "ColCount")]
    private int ColCount;

    [JsonProperty(PropertyName = "NodeSize")]
    private int NodeSize;

    [JsonProperty(PropertyName = "LevelNodes")]
    private List<Node> LevelNodes;

    public LevelData(int rowCount, int colCount, int nodeSize, List<Node> nodes)
    {
        RowCount = rowCount;
        ColCount = colCount;
        NodeSize = nodeSize;
        LevelNodes = nodes;
    }
}

Node类如下:

[JsonObject(MemberSerialization.OptIn)]
public class Node
{
    [JsonProperty(PropertyName = "ID")]
    private int mId;

    [JsonProperty(PropertyName = "Position")]
    private Vector2 mPosition;

    [JsonProperty(PropertyName = "Type")]
    private NodeType mType;

    [JsonProperty(PropertyName = "Neighbours")]
    private List<int> mNeighbours;

    ....
}

我还有一个Windows Phone xna游戏,它可以读取从地图编辑器创建的Json数据,也可以使用Json.Net(用于Windows手机)。这个游戏有LevelData和Node,它们与Map Editor结构和类完全相同。

Json.Net为.Net 4和windows phone提供了不同的lib。但是,它们似乎没有相同的功能。当Windows手机游戏读入从地图编辑器创建的json数据时,它无法反序列化数据,并出现以下错误:

Error getting value from 'mRowCount' on 'LevelData'.

在调试窗口中打印出以下内容:

 A first chance exception of type 'System.FieldAccessException' occurred in mscorlib.dll
 A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
 A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll

我可以通过将成员变量设为public而不是private来解决此问题。但后来它抱怨说它无法识别Vector2:

Error converting value "12, 12" to type 'Microsoft.Xna.Framework.Vector2'. Line 8, position 27.

在调试窗口中打印出以下内容:

A first chance exception of type 'System.Exception' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll

地图编辑器创建的Json数据在哪里:

{
    "RowCount": 20,
    "ColCount": 20,
    "NodeSize": 25,
    "LevelNodes": [
        {
            "ID": 1,
            "Position": "12, 12",
            "Type": 1,
            "Neighbours": [
                2,
                21
            ]
        }
    ],
    "Buildings": []
}

编辑:以下是我对数据进行序列化和反序列化的方法。

String json = Json.ConvertToJson<LevelData>(levelData);

public static class Json
{
    // Serialize Object to Json
    public static string ConvertToJson<T>(T obj)
    {
        return JsonConvert.SerializeObject(obj, Formatting.Indented);
    }

    public static T ConvertFromJson<T>(string json)
    {
        T result = JsonConvert.DeserializeObject<T>(json);

        return result;
    }
}

请注意:我可以在地图编辑器(.Net)中序列化和反序列化json,它支持私有json属性和Vector2。问题是当我在Windows Phone应用程序中对地图编辑器中生成的json数据进行反序列化时。

2 个答案:

答案 0 :(得分:1)

您可以尝试做的是为Vector2类型引入您自己的转换器;

[JsonObject(MemberSerialization.OptIn)]
public class Node {
  ...

  [JsonConverter(typeof(Vector2Converter))]
  public Vector2 Position { get; set; }

  ...
}

Vector2Converter是源自Json.Net的JsonConverter的类型。

public class Vector2Converter : JsonConverter {
  public override bool CanConvert(Type objectType) {
    return (objectType == typeof(Vector2));
  }

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
    return serializer.Deserialize<Vector2>(reader);
  }

  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)  {
    // Implement this if you're serialising back into JSON
    throw new NotImplementedException();
  }
}

我没有在Vector2 s的特定情况下尝试这个,所以无法确认它肯定会开箱即用。如果您的ReadJson实施中没有,您可以开始考虑使用Value上的JsonReader属性。这会返回一个object,您可以将其转换为其他类型,并可能使用来自的数据创建新的Vector2。如果这不起作用,您可能需要查看更为复杂的JsonConverter,其中您对阅读器上的令牌作出反应(TokenType等)

答案 1 :(得分:0)

对将来序列化和反序列化Vector2或其他类似对象的未来观众提供更完整的答案。我在Windows中遇到问题,而不是像OP这样的WinPhone。

可以在序列化对象本身上设置自定义Vector2反序列化器,而不是每个需要序列化的Vector2属性,如下所示:

var settings = new JsonSerializerSettings();
settings.Converters.Add(new Vector2Converter());
YourType yourObj = JsonConvert.DeserializeObject<YourType>(fileContents, settings);

这使我们不必装饰每个Vector2属性。

此外,我正在使用的转换器的完整实现,通过读取和写入实现,是:

public class Vector2Converter : JsonConverter
{
    public override bool CanConvert(Type objectType) {
        return (objectType == typeof(Vector2));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        JObject jsonObject = JObject.Load(reader);
        var properties = jsonObject.Properties().ToList();
        return new Vector2
        {
            X = (float)properties[0].Value,
            Y = (float)properties[1].Value
        };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        Vector2 v = (Vector2)value;
        writer.WriteStartObject();
        writer.WritePropertyName("X");
        serializer.Serialize(writer, v.X);
        writer.WritePropertyName("Y");
        serializer.Serialize(writer, v.Y);
        writer.WriteEndObject();
    }
}