我希望每个未指定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
更改属性。
答案 0 :(得分:3)
@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;
}
}
答案 1 :(得分:1)
我无法确定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
方法,然后检查属性是否具有属性。即使属性 具有属性,也无法保证该属性指定了新的属性名称,因此PropertyName
和UnderlyingName
之间进行了比较。如果没有属性或名称相同,则附加下划线。
我再次不确定这是否是正确的地方,但它很有效且很简单。