使用相同属性的不同名称反序列化JSON

时间:2019-03-21 08:12:06

标签: c# json class deserialization

JSON看起来像这样

{
    "123": {
        "Type": "IN",
        "OUTAgentMACID": "00-14-22-01-23-45",
        "PlateNumber": {
            "Image": "/poll/data/date0/img.png",
            "Number": "ABC1234",
            "TimeStamp": 5901291
        }
    },
    "124": {
        "Type": "OUT",
        "OUTAgentMACID": "00-14-22-01-31-45",
        "PlateNumber": {
            "Image": "/poll/data/date0/img.png",
            "Number": "ABC1234",
            "TimeStamp": 5991291
        }
    },
    "125": {
        "Type": "IN",
        "INAgentMACID": "00-14-22-01-63-45",
        "PlateNumber": {
            "Image": "/poll/data/date1/img.png",
            "Number": "ABC1234",
            "TimeStamp": 6001239
        }
    }
}

可能的类结构为

public class PlateNumber
{
    public string Image { get; set; }
    public string Number { get; set; }
    public int TimeStamp { get; set; }
}
public class Activity
{
    public string Type { get; set; }
    public string AgentMACID { get; set; }
    public PlateNumber PlateNumber { get; set; }
}
public class SessionActivity
{
    public Dictionary<int, Activity> Activities { get; set; }
}

助手看起来像这样

public class helpers : DefaultContractResolver
{
    private Dictionary<string, string> PropertyMappings { get; set; }

    public helpers()
    {
        PropertyMappings = new Dictionary<string, string>
        {
            {"INAgentMACID", "AgentMACID"},
            {"OUTAgentMACID", "AgentMACID"},
        };
    }
    protected override string ResolvePropertyName(string propertyName)
    {
        string resolvedName = null;
        var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
        return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
    }
}

现在,当我尝试像这样反序列化

        var settings = new JsonSerializerSettings();
        settings.ContractResolver = new helpers();
        var activities = JsonConvert.DeserializeObject<SessionActivity>("Some.json"), settings);

activities为空。

问题是AgentMACID,因为JSON具有OUTAgentMACIDINAgentMACID取决于Type

请帮助我为此JSON设计类。

2 个答案:

答案 0 :(得分:1)

我认为您不可能直接拥有一个表示json-的两个属性的属性(正如我在这里Make JsonPropertyAttribute allow multiple usages on same property所读)

我从这篇文章中了解到的是,您将不得不拥有另一个属性,该属性只是将值“转发”到所需属性。

示例:

    public class Activity
    {
        public string Type { get; set; }
        public string AgentMACID { get; set; }
        private string AgentMACID2 { set { AgentMACID = value; } } // used to map the other field of json
        public PlateNumber PlateNumber { get; set; }
    }

在Contract Resolver中,您必须像以前一样映射过孔。在我添加的第二个字段中,它看起来可能像这样:

   PropertyMappings = new Dictionary<string, string>
   {
       {"AgentMACID","OUTAgentMACID"},
       {"AgentMACID2","INAgentMACID"}
   };

并以此反序列化:

var activities = JsonConvert.DeserializeObject<Dictionary<int, Activity>>("json content", settings);

答案 1 :(得分:1)

1-从JSON反序列化字典

基于您的json对象:

{
    "123": {
        "Type": "IN",
        "OUTAgentMACID": "00-14-22-01-23-45",
        "PlateNumber": {
            "Image": "/poll/data/date0/img.png",
            "Number": "ABC1234",
            "TimeStamp": 5901291
        }
    },
    "124": {
        "Type": "OUT",
        "OUTAgentMACID": "00-14-22-01-31-45",
        "PlateNumber": {
            "Image": "/poll/data/date0/img.png",
            "Number": "ABC1234",
            "TimeStamp": 5991291
        }
    },
    "125": {
        "Type": "IN",
        "INAgentMACID": "00-14-22-01-63-45",
        "PlateNumber": {
            "Image": "/poll/data/date1/img.png",
            "Number": "ABC1234",
            "TimeStamp": 6001239
        }
    }
}

您可以使用:反序列化字典:

var activities = JsonConvert.DeserializeObject<Dictionary<int, Activity>>("Some.json"), settings);

2.1-在一个C#属性中管理多个json属性名称

对于第二个问题,您可以像这样定义Activity类:

public class Activity
{
    public string Type { get; set; }
    public string AgentMACID { get; set; }
    // Optional: you can rename your property with this property attribute
    // [JsonProperty("INAgentMACID")]
    public string INAgentMACID { set { AgentMACID = value; } }
    // Optional: you can rename your property with this property attribute
    // [JsonProperty("OUTAgentMACID")]
    public string OUTAgentMACID { set { AgentMACID = value; } }
    public PlateNumber PlateNumber { get; set; }
}

2.2-您还可以像执行操作一样继承DefaultContractResolver:

public class RenamePropertySerializerContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, HashSet<string>> _ignores;
    private readonly Dictionary<Type, Dictionary<string, string>> _renames;

    public RenamePropertySerializerContractResolver()
    {
        _renames = new Dictionary<Type, Dictionary<string, string>>();
    }

    public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
    {
        if (!_renames.ContainsKey(type))
            _renames[type] = new Dictionary<string, string>();

        _renames[type][propertyName] = newJsonPropertyName;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
            property.PropertyName = newJsonPropertyName;

        return property;
    }

    private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
    {
        Dictionary<string, string> renames;

        if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
        {
            newJsonPropertyName = null;
            return false;
        }

        return true;
    }
}

最后使用您新的ContractResolver:

var jsonResolver = new RenamePropertySerializerContractResolver();
jsonResolver.RenameProperty(typeof(Activity), "INAgentMACID", "AgentMACID");
jsonResolver.RenameProperty(typeof(Activity), "OUTAgentMACID", "AgentMACID");

var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;

var activities = JsonConvert.DeserializeObject<IDictionary<int, Activity>>(json, serializerSettings);

来源:https://blog.rsuter.com/advanced-newtonsoft-json-dynamically-rename-or-ignore-properties-without-changing-the-serialized-class/