在C#中没有字段名称时反序列化json字符串

问题描述

通常,当我使用API​​并获取Json字符串时,我只是简单地制作一个适合该字符串的类,然后使用newton JsonConvert.DeserializeObject填充该类。

但是我现在有一个Json字符串,其中的1个字段没有名称

{
    "attacks": {
        "114862720": {
            "code": "115dc2b990153c41c33d519b26cc302a","timestamp_started": 1596782220,"timestamp_ended": 1596782226,"attacker_id": 580816,"attacker_name": "chedders","attacker_faction": 32585,"attacker_factionname": "Heart of a Pirate","defender_id": 65306,"defender_name": "-Clansdancer","defender_faction": 0,"defender_factionname": null,"result": "Attacked","stealthed": 0,"respect_gain": 4.14,"chain": 3,"modifiers": {
                "fairfight": 3,"war": 1,"retaliation": 1,"groupAttack": 1,"overseas": 1,"chainBonus": 1
            }
        },"114862829": {
            "code": "8bf08c8ceb9b72f05f40235310cd822e","timestamp_started": 1596782339,"timestamp_ended": 1596782344,"defender_id": 964979,"defender_name": "brko21","respect_gain": 4.11,"chain": 4,"chainBonus": 1
            }
        }
    }
}

攻击后的ID是每个条目唯一的ID。因此我通常为此目的建立一个类,因为ID是未知的。

任何欢迎使用该字符串反序列化的指针。

解决方法

您可以使用[JsonExtensionData]属性。

这是官方示例:

public class DirectoryAccount
{
    // normal deserialization
    public string DisplayName { get; set; }

    // these properties are set in OnDeserialized
    public string UserName { get; set; }
    public string Domain { get; set; }

    [JsonExtensionData]
    private IDictionary<string,JToken> _additionalData;

    [OnDeserialized]
    private void OnDeserialized(StreamingContext context)
    {
        // SAMAccountName is not deserialized to any property
        // and so it is added to the extension data dictionary
        string samAccountName = (string)_additionalData["SAMAccountName"];

        Domain = samAccountName.Split('\\')[0];
        UserName = samAccountName.Split('\\')[1];
    }

    public DirectoryAccount()
    {
        _additionalData = new Dictionary<string,JToken>();
    }
}

因此,在您的OnDeserializing方法中,您可以从字典中获取值并将其添加到适当的字段中/并将其投射到对象列表等中。

,

这将反序列化为Dictionary<string,Attack>。其中,Attack是一种类型,您可以在JSON文档中使用每个对象内的所有属性对其进行定义。

此示例假设您正在使用NewtonSofts JSON库:

var attacks = JsonConvert.DeserializeObject<Dictionary<string,Attack>>(jsonString);

public class Attack {
    [JsonProperty("code")]
    public string Code { get; set; }

    [JsonProperty("timestamp_started")]
    public long TimestampStarted { get; set; }

    [JsonProperty("timestamp_ended")]
    public long TimestampEnded { get; set; }

    [JsonProperty("attacker_id")]
    public int AttackerId { get; set; }

    [JsonProperty("attacker_name")]
    public string AttackerName { get; set; }

    [JsonProperty("attacker_faction")]
    public int AttackerFaction { get; set; }

    [JsonProperty("attacker_factionname")]
    public string AttackerFactionName { get; set; }

    [JsonProperty("defender_id")]
    public int DefenderId { get; set; }

    [JsonProperty("defender_name")]
    public string DefenderName { get; set; }

    [JsonProperty("defender_faction")]
    public int DefenderFaction { get; set; }

    [JsonProperty("defender_factionname")]
    public string DefenderFactionName { get; set; }

    [JsonProperty("result")]
    public string Result { get; set; }

    [JsonProperty("stealthed")]
    public int Stealthed { get; set; }

    [JsonProperty("respect_gain")]
    public decimal RespectGain { get; set; }

    [JsonProperty("chain")]
    public int Chain { get; set; }

    [JsonProperty("modifiers")]
    public Dictionary<string,int> Modifiers { get; set; }
}

这将导致针对强类型字段集的标识符集合。

var allAttacksByFaction = attacks.Where(x => x.Value.AttackerFaction == 1234);
var singleAttack = attacks.Single(x => x.Key == "<value of attack identifier>");
,

尝试使用此json转换器。

class AttacksConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Attacks[]);
    }

    public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
    {
        JObject attacks = serializer.Deserialize<JObject>(reader);
        Dictionary<string,AttackDetails> result = new Dictionary<string,AttackDetails>();

        foreach (JProperty property in attacks.Properties())
        {
            string attackKey = property.Name;
            Attacks attackValue = property.Value.ToObject<Attacks>();
            
            result.Add(attackKey,new AttackDetails()
            {
                Code = attackValue.Code
            });
        }

        return result;
    }


    public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

完整代码可在此处找到:https://github.com/tmutton/StackOverflowQuestion63544325