Json.Net中的私人制定者

Dan*_*iel 81 c# json.net

我知道有一个属性来处理私有的setter但我有点想把这个行为作为默认值,有没有办法实现这个?除了调整来源.如果有这样的设置会很棒.

Sae*_*ini 99

我来到这里寻找实际属性,使得Json.NET在反序列化时填充readonly属性,这很简单[JsonProperty],例如:

[JsonProperty]
public Guid? ClientId { get; private set; }
Run Code Online (Sandbox Code Playgroud)

替代方案

只需提供一个具有与您的属性匹配的参数的构造函数:

public class Foo
{
    public string Bar { get; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这个工作:

string json = "{ \"bar\": \"Stack Overflow\" }";

var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow
Run Code Online (Sandbox Code Playgroud)

我更喜欢这种方法,因为:

  • 它不需要您使用属性装饰属性.
  • 它适用于两者{ get; private set; }和公正{ get; }.

  • 只是一个小小的注释:它适用于`{get; private set;}`,而不是`{get;}` (16认同)
  • 只是一点点更新.现在它也适用于{get;}; (7认同)
  • @tymtam用这个替代方案和一个例子更新了答案. (2认同)

Dan*_*iel 72

更新,新答案

我为此编写了一个源代码分发NuGet,它安装了一个带有两个自定义契约解析器的文件:

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

安装NuGet:

Install-Package JsonNet.PrivateSettersContractResolvers.Source
Run Code Online (Sandbox Code Playgroud)

然后只使用任何解析器:

var settings = new JsonSerializerSettings
{
    ContractResolver = new PrivateSetterContractResolver()
};

var model = JsonConvert.DeserializeObject<Model>(json, settings);
Run Code Online (Sandbox Code Playgroud)

你可以在这里阅读:http://danielwertheim.se/json-net-private-setters-nuget/

GitHub库:https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers

旧答案(仍然有效)

有两种方法可以解决问题.

替代1:在反序列化器上

ContractResolver.DefaultMembersSearchFlags =
                             DefaultMembersSearchFlags | BindingFlags.NonPublic;
Run Code Online (Sandbox Code Playgroud)

默认序列化选项支持所有类型的类成员.因此,此解决方案将返回所有私有成员类型,包括字段 我只对支持私人制定者感兴趣.

Alt2:创建自定义ContractResolver:

因此,这是更好的选择,因为我们只检查属性.

public class SisoJsonDefaultContractResolver : DefaultContractResolver 
{
    protected override JsonProperty CreateProperty(
        MemberInfo member,
        MemberSerialization memberSerialization)
    {
        //TODO: Maybe cache
        var prop = base.CreateProperty(member, memberSerialization);

        if (!prop.Writable)
        {
            var property = member as PropertyInfo;
            if (property != null)
            {
                var hasPrivateSetter = property.GetSetMethod(true) != null;
                prop.Writable = hasPrivateSetter;
            }
        }

        return prop;
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请阅读我的帖子:http://danielwertheim.se/json-net-private-setters/

  • 用c#6,`{get; }`不等于`{get; 私人集; }`.对于第一种方式,`property.GetSetMethod(true)`返回`null`,后者返回`true`.这让我感到惊讶.您必须使用`private set;`进行反序列化才能按预期工作. (4认同)
  • 链接到您的帖子http://daniel.wertheim.se/2010/11/06/json-net-private-setters/ (2认同)

Tod*_*ier 13

@ Daniel的答案(Alt2)很有用,但是我需要这个才能为私有的setter和getter工作(我正在使用一个实际上只有一些只写东西的API user.password.)这就是我最终得到的结果:

public class NonPublicPropertiesResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        var prop = base.CreateProperty(member, memberSerialization);
        if (member is PropertyInfo pi) {
            prop.Readable = (pi.GetMethod != null);
            prop.Writable = (pi.SetMethod != null);
        }
        return prop;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样注册:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
    ContractResolver = new NonPublicPropertiesResolver()
};
Run Code Online (Sandbox Code Playgroud)


Ale*_*aus 12

从 C# 9 开始,建议在从 JSON 初始化对象时使用Init Only Setters而不是私有 Setters。例如public string Summary { get; init; }

如果您坚持使用私有设置器,那么您需要使用JsonInclude属性来注释此类属性。

无论哪种方式,JsonSerializer.DeserializeAsync都会反序列化属性。

  • `[JsonIninclude]` 有效,谢谢! (2认同)