且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

无法反序列化我的json

更新时间:2022-05-01 07:27:45

您可以使用,只要您使用的字符串数组中只有一次,并且对象本身表示为值数组,内部数组与结构数组成1-1对应.

You can use json.net to deserialize and re-serialize a List<LocationChannelEvent> in the format shown as long as you use a custom JsonConverer. This is required because, by default, a collection of objects is serialized from and to a JSON array, but in your JSON, a collection of objects is being serialized in a slightly more compact form of a single object where the object property names are serialized only once in an array of strings called "structure", and the objects themselves are represented as an array of array of values, the inner arrays being in 1-1 correspondence to the structure array.

因此,如果您创建以下转换器:

Thus, if you create the following converter:

public class StructuredListConverter<T> : JsonConverter
{
    const string typeName = "type";
    const string structureName = "structure";
    const string listName = "list";

    public override bool CanConvert(Type objectType)
    {
        if (!typeof(ICollection<T>).IsAssignableFrom(objectType))
            return false;
        // This converter is only implemented for read/write collections.  So no arrays.
        if (objectType.IsArray)
            return false; 
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var collection = existingValue as ICollection<T> ?? (ICollection<T>) serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
        var root = JObject.Load(reader);
        var structure = root[structureName] == null ? null : root[structureName].ToObject<string []>();
        if (structure == null)
            throw new JsonSerializationException("structure not found.");
        var listToken = root[listName];
        if (listToken == null || listToken.Type == JTokenType.Null)
            return collection;
        var list = listToken as JArray;
        if (list == null)
            throw new JsonSerializationException("list was not an array.");
        if (list == null || list.Count == 0)
            return collection;
        foreach (var item in list)
        {
            if (item == null || item.Type == JTokenType.Null)
                collection.Add(default(T));
            else if (item.Type != JTokenType.Array)
                throw new JsonSerializationException(string.Format("Item was not an array: {0}", item));
            else
                collection.Add(new JObject(item.Zip(structure, (i, n) => new JProperty(n, i))).ToObject<T>());
        }
        return collection;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var contract = serializer.ContractResolver.ResolveContract(typeof(T)) as JsonObjectContract;
        if (contract == null)
            throw new JsonSerializationException(string.Format("Type {0} is not mapped to a JSON object.", typeof(T)));

        var collection = (ICollection<T>)value;
        writer.WriteStartObject();

        // Write item type
        writer.WritePropertyName(typeName);
        serializer.Serialize(writer, typeof(T));

        // Write structure (property names)
        var structure = contract.Properties.Where(p => p.Readable && !p.Ignored).Select(p => p.PropertyName).ToList();
        writer.WritePropertyName(structureName);
        serializer.Serialize(writer, structure);

        // Write array of array of values
        var query = collection
            .Select(i => i == null ? null : contract.Properties.Where(p => p.Readable && !p.Ignored).Select(p => p.ValueProvider.GetValue(i)));
        writer.WritePropertyName(listName);
        serializer.Serialize(writer, query);

        writer.WriteEndObject();
    }
}

并按如下所示定义数据模型:

And define your data model as follows:

public class LocationChannelEvent : Activity.Channel.Event
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public float? Distance { get; set; }
    public float? Altitude { get; set; }

    /// <summary>
    /// Speed in m/s
    /// </summary>
    public float? Speed { get; set; }
}

public class Location
{
    [JsonConverter(typeof(StructuredListConverter<LocationChannelEvent>))]
    public List<LocationChannelEvent> events { get; set; }
}

public class RootObject
{
    public Location location { get; set; }
}

您将能够反序列化并重新序列化所显示的JSON.

You will be able to deserialize and re-serialize the JSON shown.

原型小提琴.