【发布时间】:2010-11-01 06:08:44
【问题描述】:
我知道有一个属性可以处理私有设置器,但我有点希望这种行为作为默认值,有没有办法做到这一点?除了调整源。如果有这个设置就好了。
【问题讨论】:
我知道有一个属性可以处理私有设置器,但我有点希望这种行为作为默认值,有没有办法做到这一点?除了调整源。如果有这个设置就好了。
【问题讨论】:
我来这里是为了寻找使 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;}
我为此编写了一个源代码分发 NuGet,它安装了一个带有两个自定义合同解析器的文件:
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/
【讨论】:
DefaultMembersSearchFlags 一直是 deprecated。
{get; } 不等同于 { get; private set; }。第一种方式property.GetSetMethod(true) 返回null,后者返回true。这让我很惊讶。您必须拥有 private set; 才能使反序列化按预期工作。
@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()
};
【讨论】:
从 C# 9 开始,在从 JSON 初始化对象时,建议使用 Init Only Setters 而不是私有 setter。例如。 public string Summary { get; init; }
如果您坚持使用私有 setter,则需要使用 JsonInclude 属性注释此类属性。
无论哪种方式,JsonSerializer.DeserializeAsync 都会反序列化属性。
【讨论】:
在撰写这篇文章时,文档对此有何评论:
默认情况下,Json.NET 将首先查找一个带有 JsonConstructorAttribute 标记的构造函数,然后查找一个公共默认构造函数(一个不带任何参数的构造函数),然后检查该类是否有一个带参数的公共构造函数最后检查一个非公共的默认构造函数。
意思是如果你有默认构造函数(没有参数),那么它将被选择而不是任何其他构造函数。这可以通过使用JsonConstructorAttribute 装饰所需的构造函数来解决。
另外说明 - 使用 JsonProperty 装饰属性对我来说无论有没有构造函数都不起作用。
【讨论】: