【问题标题】:JsonConvert DeserializeObject case sensitive [duplicate]JsonConvert DeserializeObject区分大小写[重复]
【发布时间】:2016-08-03 22:23:24
【问题描述】:

我正在尝试将字符串内容反序列化为对象,但我希望内容区分大小写。只有当字符串具有小写属性时,代码才会成功,如果字符串具有大写属性,则代码会失败。以下是类:

internal class ResponseList
{
    [DataMember]
    [JsonProperty]
    internal List<Response> Value { get; set; }
}

internal class Response
{
    [DataMember]
    [JsonProperty]
    internal string Id { get; set; }

    [DataMember]
    [JsonProperty]
    internal string Location { get; set; }

    [DataMember]
    [JsonProperty]
    internal PlanClass Plan { get; set; }
}

internal class PlanClass
{
    [DataMember]
    [JsonProperty]
    internal string Name { get; set; }

    [DataMember]
    [JsonProperty]
    internal string Product { get; set; }

    [DataMember]
    [JsonProperty]
    internal string Publisher { get; set; }
}

以下是我的代码。但这不区分大小写。大写和小写都成功:

string content = File.ReadAllText(contentFilePath);
JsonSerializerSettings jsonSerializerSettings1 = new JsonSerializerSettings()
{
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};
ResponseList response = (ResponseList)JsonConvert.DeserializeObject(contentResourceOutput, typeof(ResponseList), Constants.JsonSerializerSettings);

代码只有在内容为:

{
  "value": [
    {
      "id": "id1",
      "location": "location1",
      "plan": {
        "name": "free",
        "product": "product1",
        "publisher": "publisher1"
      }
    }
    ]
}

即使其中一个键是大写字母也会失败。例如。

{
  "value": [
    {
      "Id": "id1",
      "Location": "location1",
      "plan": {
        "Name": "free",
        "product": "product1",
        "publisher": "publisher1"
      }
    }
    ]
}

请注意,只有键/属性名称应为小写。这些值可以是大写。 有没有办法让 JsonConvert.Deserializeobject 区分大小写?

【问题讨论】:

    标签: c# json serialization deserialization case-sensitive


    【解决方案1】:

    您可以编写一个自定义转换器来处理这个用例。关于您需要对所有键名进行递归检查,我使用了 Thyminehere 给出的精彩 WalkNode 答案。

    var json = @"{""id"": ""id1"",""name"": ""name1"",""type"": ""type1""}";
    var json2 = @"{""id"": ""id1"",""Name"": ""name1"",""type"": ""type1""}";
    
    JsonSerializerSettings settings = new JsonSerializerSettings()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Converters = new List<JsonConverter> { new CamelCaseOnlyConverter() }
    };
    
    var response = JsonConvert.DeserializeObject<Response>(json, settings);
    var response2 = JsonConvert.DeserializeObject<Response>(json2, settings);
    
    public class CamelCaseOnlyConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return true;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, 
            object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
    
            var token = (JObject)JToken.Load(reader);
    
            var isCamelCased = true;
            WalkNode(token, null,
            t =>
            {
                var nameFirstChar = t.Name[0].ToString();
                if (!nameFirstChar.Equals(nameFirstChar.ToLower(), 
                    StringComparison.CurrentCulture))
                {
                    isCamelCased = false;
                    return;
                }
            });
    
            if (!isCamelCased) return null;
    
            return token.ToObject(objectType);
        }
    
        public override void WriteJson(JsonWriter writer, object value, 
            JsonSerializer serializer)
        {
            JObject o = (JObject)JToken.FromObject(value);
            o.WriteTo(writer);
        }
    
        private static void WalkNode(JToken node,
                                Action<JObject> objectAction = null,
                                Action<JProperty> propertyAction = null)
        { 
            if (node.Type == JTokenType.Object)
            {
                if (objectAction != null) objectAction((JObject)node);
                foreach (JProperty child in node.Children<JProperty>())
                {
                    if (propertyAction != null) propertyAction(child);
                    WalkNode(child.Value, objectAction, propertyAction);
                }
            }
            else if (node.Type == JTokenType.Array)
                foreach (JToken child in node.Children())
                    WalkNode(child, objectAction, propertyAction);
        }
    }
    

    第一个字符串将返回一个水合对象。第二个字符串将提前终止,返回 null。

    【讨论】:

    • @Romonov 确定。更新后的答案将正确拒绝第二个字符串。
    • 这完美!
    • @Romonov 真棒,乐于助人:)
    • 如果你在 xUnit 测试中使用它并在 JsonConvert 上设置 defaultSettings,它会导致堆栈溢出异常(我第一次在 SO 上发布了一个 SO,很酷)
    猜你喜欢
    • 2021-12-22
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 2014-02-05
    • 2011-02-11
    • 1970-01-01
    • 2021-08-16
    相关资源
    最近更新 更多