Json.Net中的私人二传手


93

我知道有一个属性可以处理私人二传手,但我有点想将此行为作为默认设置,有没有办法做到这一点?除了调整源。如果有这个设置,那就太好了。


1
我一直在寻找这个那个答案。
marbel82'9

Answers:


112

我来这里是为了寻找使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

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

  • 它不需要您用属性装饰属性。
  • 它既适用于Just { get; private set; }也适用{ get; }

19
只是一个小小的提示:它与{get;private set;},不与{get;}
tymtam

8
只是一点点更新。现在它也可以与{get;};一起使用。
HAV

1
@Hav以后是什么版本?我刚刚测试了v11.0.2,它无法正常运行{get;}
tymtam

1
@tymtam我认为,只有{ get; }在类型具有带有与属性名称匹配的参数的构造函数时,它才可以使用。
Saeb Amini

2
@tymtam使用此替代方法和示例更新了答案。
萨卜·阿米尼

77

更新,新答案

我为此编写了一个源代码分发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/




1
看起来Alt 2绝对是当今的发展之路。DefaultMembersSearchFlags弃用
Todd Menier 2015年

4
使用c#6时,{get; }不等同于{ get; private set; }。对于第一种方式,property.GetSetMethod(true)返回null,而第二种true。这让我感到惊讶。必须具有private set;反序列化才能按预期工作。
点缀

看起来Install-Package JsonNet.ContractResolvers应该现在使用。github.com/danielwertheim/jsonnet-contractresolvers
对齐

14

@Daniel的答案(Alt2)是正确的,但是我需要它同时适用于私有设置者和获取者(我正在使用的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()
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.