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

RAM*_*RAM 1 c# json.net

A)

我有一个 DLL 库,其中包含一个类,如下所示:

public class Thing
{
    // OTHER_PROPERTIES

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

    [JsonProperty(Required = Required.Always)]
    public bool IsBook { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

假设:无法访问该类的源代码Thing


二)

我有一个像这样的 JSON:

{
    OTHER_PROPERTIES
}
Run Code Online (Sandbox Code Playgroud)

注意:没有一对名称/值IsBook

假设:不会更改JSON包含IsBook在其中的内容。


C)

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

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


问题:

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

Evk*_*Evk 6

您可以使用自定义合同解析器来实现这一点。例如:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

进而:

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

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

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

您可以仅将特定类的特定属性设为非必需(而不是像上面的示例中那样全部):

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\"}");
Run Code Online (Sandbox Code Playgroud)

以及上面的整体调整示例,但是您希望适合您的特定用例。