Json.Net中的私人制定者

时间:2010-11-01 06:08:44

标签: json.net

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

5 个答案:

答案 0 :(得分:75)

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

[JsonProperty]
public Guid? ClientId { get; private set; }

替代解决方案

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

public class Foo
{
    public string Bar { get; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}

现在可行:

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

var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow

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

  • 它不要求您使用属性装饰属性。
  • 适用于{ get; private set; }{ get; }

答案 1 :(得分:64)

更新,新答案

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

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

安装NuGet:

Install-Package JsonNet.PrivateSettersContractResolvers.Source

然后只使用任何一个解析器:

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

var model = JsonConvert.DeserializeObject<Model>(json, settings);

您可以在此处阅读:http://danielwertheim.se/json-net-private-setters-nuget/

GitHub回购:https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers

旧答案(仍然有效)

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

替代1:在反序列化器上

ContractResolver.DefaultMembersSearchFlags =
                             DefaultMembersSearchFlags | BindingFlags.NonPublic;

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

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;
    }
}

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

答案 2 :(得分:12)

@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;
    }
}

如此注册:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
    ContractResolver = new NonPublicPropertiesResolver()
};

答案 3 :(得分:1)

在撰写本文时,文档对此有何评论:

<块引用>

默认情况下,Json.NET 将首先查找标有 JsonConstructorAttribute 的构造函数,然后查找公共默认构造函数(不带任何参数的构造函数),然后检查该类是否具有带参数的单个公共构造函数最后检查一个非公共的默认构造函数。

也就是说,如果您有默认构造函数(没有参数),那么它将被选择而不是任何其他构造函数。这可以通过使用 JsonConstructorAttribute 装饰所需的构造函数来解决。

另外说明 - 使用 JsonProperty 装饰属性对我来说不管有没有构造函数都不起作用。

答案 4 :(得分:0)

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

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

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