如何在不更改json及其相应类的情况下解决“在json中找不到必需属性”错误?

时间:2018-04-07 14:36:51

标签: c# json.net

A)

我有一个DLL库,包括一个类似下面的代码:

public class Thing
{
    // OTHER_PROPERTIES

    //..........................

    [JsonProperty(Required = Required.Always)]
    public bool IsBook { get; set; }
}
  

假设:访问Thing类的来源。

B)

我有一个像这样的JSON:

{
    OTHER_PROPERTIES
}
  

注意: IsBook

的一对名称值      

假设:不会更改JSON以包含IsBook

C)

如果我运行JsonConvert.DeserializeObject<Thing>(json);,则会收到以下错误:

  

错误:在json ....中找不到必需的属性。

问题:

如何通过观察问题的假设来编写自定义代码来解决上述错误? (在写完答案之前,请再次阅读上述假设。)

1 个答案:

答案 0 :(得分:1)

您可以使用自定义合约解析程序来实现这一目标。例如:

public class Thing
{
    [JsonProperty("Name")]
    public string Name { get; set; }
    [JsonProperty(Required = Required.Always)]
    public bool IsBook { get; set; }
}

class NeverRequiredContractResolver : DefaultContractResolver {
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        var prop = base.CreateProperty(member, memberSerialization);
        prop.Required = Required.Default;
        return prop;
    }
}

然后:

var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}",
    new JsonSerializerSettings {
        ContractResolver = new NeverRequiredContractResolver()
    });

当然,您可以全局分配解析器,而不是将其传递给每个DeserializeObject

JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
    ContractResolver = new NeverRequiredContractResolver()
};
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}");

你只能制作非必需的特定类的特定属性(而不是像上面的例子中的所有属性):

class CustomPropertyContractResolver : DefaultContractResolver {
    private readonly Action<MemberInfo, JsonProperty> _propFixup;
    public CustomPropertyContractResolver(Action<MemberInfo, JsonProperty> propFixup) {
        _propFixup = propFixup;
    }
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        var prop = base.CreateProperty(member, memberSerialization);
        _propFixup?.Invoke(member , prop);
        return prop;
    }
}

JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
    ContractResolver = new CustomPropertyContractResolver((member, prop) => {
        if (member.DeclaringType == typeof(Thing) && member.Name == "IsBook") {
            prop.Required = Required.Default;
        }
    })
};
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}");

并根据您的具体使用情况对上述整体进行调整。