我知道有一个属性可以处理私有的setter,但我想默认情况下采用这种行为,有没有办法实现这一点?除了调整源代码以外。如果有设置可以做到这点就太好了。
我来到这里是为了寻找让Json.NET在反序列化时填充只读属性的实际属性,那就是简单的[JsonProperty]
,例如:
我来到这里是为了寻找使 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;}
。 - tymtam{get;}
的属性,它唯一的机会就是使用构造函数,因此您需要提供一个具有匹配参数名称的构造函数。请参阅此答案以获取更多详细信息。 - Saeb Amini我为此编写了一个源分发NuGet,它安装了一个包含两个自定义合同解析器的单个文件:
安装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
有两个替代方案可以解决这个问题。
替代方案1:对反序列化器进行设置
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
默认序列化选项支持所有类型的类成员。因此,这个解决方案将返回所有私有成员类型,包括字段。我只对支持私有 setter 的内容感兴趣。
备选方案2:创建自定义 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/
{get;}
并不等同于{ get; private set; }
。对于第一种方式,property.GetSetMethod(true)
返回值为null
,而对于后者则为true
。这让我感到惊讶。你必须要有private set;
才能使反序列化按预期工作。 - emragins @Daniel的回答(Alt2)非常准确,但我需要它适用于私有setter和getter(我正在使用一个实际上有一些只写入事物的API,比如 user.password )。这是我最终得出的:
<code>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;
}
}
</code>
已注册如下:
<code>JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
ContractResolver = new NonPublicPropertiesResolver()
};
</code>
public string Summary { get; init; }
如果您坚持使用私有setters,则需要使用JsonInclude属性注释此类属性。[JsonInclude]
已经生效,谢谢! - bzmind根据撰写此文章时的文档,以下是相关内容:
默认情况下,Json.NET首先寻找一个用JsonConstructorAttribute标记的构造函数,然后查找一个公共默认构造函数(不带任何参数的构造函数),然后检查该类是否具有单个带参数的公共构造函数,最后检查非公共默认构造函数。
这意味着如果您有默认构造函数(没有参数),那么它将优先于其他构造函数被选择。可以通过使用JsonConstructorAttribute
装饰所需的构造函数来解决此问题。
另外需要注意的是- 使用JsonProperty
装饰属性对我来说无论是否有构造函数都不起作用。