【问题标题】:ContractResolver can alter the mapped propertyContractResolver 可以改变映射的属性
【发布时间】:2014-09-04 16:47:39
【问题描述】:

我希望每个未指定 JsonPropertyAttribute 的属性都遵循自定义合同。但是,如果指定了,那就应该是这样。

但如果我有一个映射属性并且正在使用自定义合同解析器,那么合同解析器可以更改映射属性。

例如,当指定 JsonProperty("hello") 时,我应该在 JSON 输出中看到 hello。相反,我看到了hello_。我提交了issue,但被告知要覆盖更高的方法,但不是哪个。

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace DeserializeTest
{
    class Program
    {
        static void Main()
        {
            var json = new JObject(new JProperty("hello", "world"));

            var settings = new JsonSerializerSettings { ContractResolver = new CustomContractResolver() };
           var a = JsonConvert.DeserializeObject<Test>(json.ToString(), settings);
        }
    }

    public class Test
    {
        [JsonProperty("hello")]
        public string FooBar { get; set; }
    }

    public class CustomContractResolver : DefaultContractResolver
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            return propertyName + "_";
        }
    }
}

那么我如何让 Json.NET 在指定时始终使用(而不是更改)JsonProperty

现实世界的例子:我正在使用SnakeCamelCaseContractResolver。它在文本和数字之间添加下划线。这模仿了 Rails 的序列化方式。但是在不遵循规范的情况下,例如address1,我需要能够防止SnakeCamelCaseContractResolver 更改属性。

【问题讨论】:

    标签: c# json.net


    【解决方案1】:

    @Andrew Whitaker 在这里有正确的想法。我要补充一点,如果您想让SnakeCamelCaseContractResolver 示例正常工作,您可以将实现更改为以下内容。请注意,它会覆盖 CreateProperty 而不是 ResolvePropertyName

    class SnakeCaseContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty prop = base.CreateProperty(member, memberSerialization);
    
            // if the property does not have a JsonPropertyAttribute applied, use Snake Case
            if (!member.CustomAttributes.Any(att => att.AttributeType == typeof(JsonPropertyAttribute)))
            {
                prop.PropertyName = GetSnakeCase(prop.PropertyName);
            }
    
            return prop;
        }
    
        private string GetSnakeCase(string input)
        {
            if (string.IsNullOrEmpty(input))
                return input;
    
            var buffer = "";
    
            for (var i = 0; i < input.Length; i++)
            {
                var isLast = (i == input.Length - 1);
                var isSecondFromLast = (i == input.Length - 2);
    
                var curr = input[i];
                var next = !isLast ? input[i + 1] : '\0';
                var afterNext = !isSecondFromLast && !isLast ? input[i + 2] : '\0';
    
                buffer += char.ToLower(curr);
    
                if (!char.IsDigit(curr) && char.IsUpper(next))
                {
                    if (char.IsUpper(curr))
                    {
                        if (!isLast && !isSecondFromLast && !char.IsUpper(afterNext))
                            buffer += "_";
                    }
                    else
                        buffer += "_";
                }
    
                if (!char.IsDigit(curr) && char.IsDigit(next))
                    buffer += "_";
                if (char.IsDigit(curr) && !char.IsDigit(next) && !isLast)
                    buffer += "_";
            }
    
            return buffer;
        }
    }
    

    演示https://dotnetfiddle.net/Iqz9cA

    【讨论】:

      【解决方案2】:

      我无法确定 JNK 的“更高级别方法”究竟是什么意思,但这里有一个覆盖 CreateProperty 的尝试:

      public class CustomContractResolver : DefaultContractResolver
      {
          protected override JsonProperty CreateProperty(
              MemberInfo member, MemberSerialization memberSerialization)
          {
              JsonProperty property = base.CreateProperty(member, memberSerialization);
      
              if (!property.HasMemberAttribute || 
                  property.PropertyName == property.UnderlyingName)
              {
                  property.PropertyName += "_";
              }
      
              return property;
          }
      }
      

      基本上,调用基类的CreateProperty方法,然后检查属性是否有属性。即使属性确实有一个属性,也不能保证该属性指定了一个新的属性名称,因此PropertyNameUnderlyingName 之间的比较。如果没有属性或名称相同,则附加下划线。

      再次,我不确定这是否是执行此操作的正确位置,但它有效且足够简单。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-06
        • 2021-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多