虽然我发现了很多方法来反序列化特定属性,同时阻止它们序列化,但我正在寻找相反的行为。
我发现有很多问题要求反过来:
Making a property deserialize but not serialize with json.net
Can I instruct Json.NET to deserialize, but not serialize, specific properties?
JSON.Net - Use JsonIgnoreAttribute only on serialization (But not when deserialzing)
如何序列化特定属性,但阻止它反序列化回POCO?是否有可用于装饰特定属性的属性?
基本上我正在寻找与反序列化相当的ShouldSerialize *方法。
我知道我可以写一个自定义转换器,但这似乎有点过分了。
编辑:
这里有更多的背景。这背后的原因是我的班级看起来像:
public class Address : IAddress
{
/// <summary>
/// Gets or sets the two character country code
/// </summary>
[JsonProperty("countryCode")]
[Required]
public string CountryCode { get; set; }
/// <summary>
/// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c>
/// </summary>
[JsonProperty("countryProvinceState")]
public string CountryProvinceState
{
get
{
return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState);
}
set
{
if (!string.IsNullOrWhiteSpace(value) && value.Contains("|"))
{
string[] valueParts = value.Split('|');
if (valueParts.Length == 2)
{
this.CountryCode = valueParts[0];
this.ProvinceState = valueParts[1];
}
}
}
}
[JsonProperty("provinceState")]
[Required]
public string ProvinceState { get; set; }
}
我需要请求的CountryProvinceState
属性,但我不希望它反序列化并触发setter逻辑。
答案 0 :(得分:17)
最简单的方法是将属性标记为[JsonIgnore]
并创建只获取代理属性:
/// <summary>
/// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c>
/// </summary>
[JsonIgnore]
public string CountryProvinceState
{
get
{
return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState);
}
set
{
if (!string.IsNullOrWhiteSpace(value) && value.Contains("|"))
{
string[] valueParts = value.Split('|');
if (valueParts.Length == 2)
{
this.CountryCode = valueParts[0];
this.ProvinceState = valueParts[1];
}
}
}
}
[JsonProperty("countryProvinceState")]
string ReadCountryProvinceState
{
get { return CountryProvinceState; }
}
如果您愿意,代理属性可以是私有的。
<强>更新强>
如果必须为许多类中的许多属性执行此操作,则可能更容易创建自己的ContractResolver
来检查自定义属性。如果找到,该属性将表示该属性是get-only:
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)]
public class GetOnlyJsonPropertyAttribute : Attribute
{
}
public class GetOnlyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property != null && property.Writable)
{
var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true);
if (attributes != null && attributes.Count > 0)
property.Writable = false;
}
return property;
}
}
然后使用它:
[JsonProperty("countryProvinceState")]
[GetOnlyJsonProperty]
public string CountryProvinceState { get; set; }
然后:
var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() };
var address = JsonConvert.DeserializeObject<Address>(jsonString, settings);
答案 1 :(得分:0)
在您的问题中,您有一个简单的字符串属性。但是,当您有一个对象时,情况会有些复杂。使用.Writeable = false
的解决方案将不起作用,因为反序列化将转到对象的属性。考虑以下代码:
public class Constants
{
public Address Headquarters { get; set; }
public static Constants Instance = new Constants
{
Headquarters = new Address { Street = "Baker Street" }
};
}
public class Address
{
public string Street { get; set; }
}
public class Data
{
[GetOnlyJsonProperty]
// we want this to be included in the response, but not deserialized back
public Address HqAddress { get { return Constants.Instance.Headquarters; } }
}
// somewhere in your code:
var data = JsonConvert.DeserializeObject<Data>("{'HqAddress':{'Street':'Liverpool Street'}}", settings);
现在JSON仍然不会尝试为Addreess
属性创建一个新的HqAddress
对象,因为它只有吸气剂。但是,然后(即使.Writeable == false
)更深入了,对Street
属性进行反序列化,将“ Liverpool Street”设置为Constants.Instance.Heqdquarters
对象,覆盖了应用程序常量中的数据。
解决方案:
在新版本的Newtonsoft.JSON(我在v10中尝试过)中,有一个新属性ShouldDeserialize
。所以解析器应该是:
public class GetOnlyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property != null) // Change here (1)
{
var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true);
if (attributes != null && attributes.Count > 0)
property.ShouldDeserialize = (a) => false; // Change here (2)
}
return property;
}
}
(1)我删除了&& property.Writeable
的条件,因此它处理HqAddress
并跳过反序列化整个树。
(2)ShouldDeserialize
是一个谓词,调用每个对象进行反序列化。因此,您可以有条件地仅跳过某些属性。但是这里我举了个简单的例子。