【问题标题】:Private setters in Json.NetJson.Net 中的私人二传手
【发布时间】:2010-11-01 06:08:44
【问题描述】:

我知道有一个属性可以处理私有设置器,但我有点希望这种行为作为默认值,有没有办法做到这一点?除了调整源。如果有这个设置就好了。

【问题讨论】:

  • 我正在寻找thisthat 的答案。

标签: c# json.net


【解决方案1】:

我来这里是为了寻找使 Json.NET 在反序列化时填充只读属性的实际属性,这就是 [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; }

【讨论】:

  • 只是一个小提示:它适用于{get;private set;},不适用于{get;}
  • 只是一点点更新。现在它也适用于 {get;};
  • @Hav 从什么版本开始?我刚刚测试了 v11.0.2,它确实 工作 {get;}
  • @tymtam 用这个替代方案和一个例子更新了答案。
【解决方案2】:

更新,新答案

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

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

安装NuGet package:

Install-Package JsonNet.ContractResolvers

然后只需使用任何解析器:

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

旧答案(仍然有效)

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

Alt 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/

【讨论】:

【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

      在撰写这篇文章时,文档对此有何评论:

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

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

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

      【讨论】:

        猜你喜欢
        • 2016-08-16
        • 1970-01-01
        • 2015-03-05
        • 1970-01-01
        • 1970-01-01
        • 2017-07-23
        • 2019-07-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多