使属性反序列化,但不能用json.net序列化
我们有一些configuration文件是通过使用Json.net序列化C#对象生成的。
我们希望将序列化类的一个属性从简单的枚举属性迁移到类属性中。
一个简单的方法是将旧的enum属性留在类中,并且在我们加载configuration时安排Json.net读这个属性,但是当我们下一个序列化对象的时候不要再保存它。 我们将分别处理从旧枚举中生成新类。
有没有简单的方法来标记(例如属性)的C#对象的属性,以便Json.net将只在序列化时忽略它,而是在反序列化时注意它呢?
实际上有几个相当简单的方法可以用来实现你想要的结果。
举个例子,假设你有你的类目前定义如下:
class Config { public Fizz ObsoleteSetting { get; set; } public Bang ReplacementSetting { get; set; } } enum Fizz { Alpha, Beta, Gamma } class Bang { public string Value { get; set; } }
你想这样做:
string json = @"{ ""ObsoleteSetting"" : ""Gamma"" }"; // deserialize Config config = JsonConvert.DeserializeObject<Config>(json); // migrate config.ReplacementSetting = new Bang { Value = config.ObsoleteSetting.ToString() }; // serialize json = JsonConvert.SerializeObject(config); Console.WriteLine(json);
要得到这个:
{"ReplacementSetting":{"Value":"Gamma"}}
方法1:添加ShouldSerialize方法
Json.NET有能力通过在类中查找相应的ShouldSerialize
方法来有条件地序列化属性。
要使用此function,请将布尔值ShouldSerializeBlah()
方法添加到您的类中,其中将Blah
replace为您不想序列化的属性的名称。 使这个方法的执行总是返回false
。
class Config { public Fizz ObsoleteSetting { get; set; } public Bang ReplacementSetting { get; set; } public bool ShouldSerializeObsoleteSetting() { return false; } }
注意:如果您喜欢这种方法,但不想通过引入ShouldSerialize
方法来ShouldSerialize
类的公共接口,则可以使用IContractResolver
以编程方式执行相同的操作。 请参阅文档中的条件属性序列化 。
方法2:用JObjects操作JSON
而不是使用JsonConvert.SerializeObject
进行序列化,将configuration对象加载到一个JObject
,然后只需从JSON中删除不需要的属性,然后写出它。 这只是一些额外的代码行。
JObject jo = JObject.FromObject(config); // remove the "ObsoleteSetting" JProperty from its parent jo["ObsoleteSetting"].Parent.Remove(); json = jo.ToString();
方法3:聪明(ab)使用属性
- 将
[JsonIgnore]
属性应用于不想被序列化的属性。 - 添加一个替代的私有属性setter到与原始属性相同的类中。 使该属性的实现设置为原始属性。
- 将
[JsonProperty]
属性应用于备用设置器,为其提供与原始属性相同的JSON名称。
这里是修改的Config
类:
class Config { [JsonIgnore] public Fizz ObsoleteSetting { get; set; } [JsonProperty("ObsoleteSetting")] private Fizz ObsoleteSettingAlternateSetter { // get is intentionally omitted here set { ObsoleteSetting = value; } } public Bang ReplacementSetting { get; set; } }
我喜欢这个属性,这里是我需要反序列化属性时使用的方法,但不是序列化它,反之亦然。
第1步 – 创build自定义属性
public class JsonIgnoreSerializationAttribute : Attribute { }
第2步 – 创build一个自定义的合同重组
class JsonPropertiesResolver : DefaultContractResolver { protected override List<MemberInfo> GetSerializableMembers(Type objectType) { //Return properties that do NOT have the JsonIgnoreSerializationAttribute return objectType.GetProperties() .Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute))) .ToList<MemberInfo>(); } }
第3步 – 添加不需要序列化但反序列化的属性
[JsonIgnoreSerialization] public string Prop1 { get; set; } //Will be skipped when serialized [JsonIgnoreSerialization] public string Prop2 { get; set; } //Also will be skipped when serialized public string Prop3 { get; set; } //Will not be skipped when serialized
第4步 – 使用它
var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });
希望这可以帮助! 另外值得注意的是,当反序列化发生时,这也将忽略这些属性,当我正在使用传统方式使用转换器时derserializing。
JsonConvert.DeserializeObject<MyType>(myString);
在我花了很长时间寻找如何标记一个类的属性是反序列化和不可序列化,我发现没有这样的事情要做的, 所以我想出了一个解决scheme,它结合了两个不同的库或序列化技术(System.Runtime.Serialization.Json&Newtonsoft.Json),它为我工作如下:
- 将所有class级和子class标记为“DataContract”。
- 将您的类和子类的所有属性标记为“DataMember”。
- 将你的类和子类的所有属性标记为“JsonProperty”,除非你希望它们不被序列化。
- 现在标记你不希望它被序列化为“JsonIgnore”的属性。
-
然后使用“Newtonsoft.Json.JsonConvert.SerializeObject”进行序列化,并使用“System.Runtime.Serialization.Json.DataContractJsonSerializer”进行反序列化。
using System; using System.Collections.Generic; using Newtonsoft.Json; using System.Runtime.Serialization; using System.IO; using System.Runtime.Serialization.Json; using System.Text; namespace LUM_Win.model { [DataContract] public class User { public User() { } public User(String JSONObject) { MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(JSONObject)); DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(User)); User user = (User)dataContractJsonSerializer.ReadObject(stream); this.ID = user.ID; this.Country = user.Country; this.FirstName = user.FirstName; this.LastName = user.LastName; this.Nickname = user.Nickname; this.PhoneNumber = user.PhoneNumber; this.DisplayPicture = user.DisplayPicture; this.IsRegistred = user.IsRegistred; this.IsConfirmed = user.IsConfirmed; this.VerificationCode = user.VerificationCode; this.Meetings = user.Meetings; } [DataMember(Name = "_id")] [JsonProperty(PropertyName = "_id")] public String ID { get; set; } [DataMember(Name = "country")] [JsonProperty(PropertyName = "country")] public String Country { get; set; } [DataMember(Name = "firstname")] [JsonProperty(PropertyName = "firstname")] public String FirstName { get; set; } [DataMember(Name = "lastname")] [JsonProperty(PropertyName = "lastname")] public String LastName { get; set; } [DataMember(Name = "nickname")] [JsonProperty(PropertyName = "nickname")] public String Nickname { get; set; } [DataMember(Name = "number")] [JsonProperty(PropertyName = "number")] public String PhoneNumber { get; set; } [DataMember(Name = "thumbnail")] [JsonProperty(PropertyName = "thumbnail")] public String DisplayPicture { get; set; } [DataMember(Name = "registered")] [JsonProperty(PropertyName = "registered")] public bool IsRegistred { get; set; } [DataMember(Name = "confirmed")] [JsonProperty(PropertyName = "confirmed")] public bool IsConfirmed { get; set; } [JsonIgnore] [DataMember(Name = "verification_code")] public String VerificationCode { get; set; } [JsonIgnore] [DataMember(Name = "meeting_ids")] public List<Meeting> Meetings { get; set; } public String toJSONString() { return JsonConvert.SerializeObject(this, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); } } }
希望有帮助…
使用setter属性:
[JsonProperty(nameof(IgnoreOnSerializing))] public string IgnoreOnSerializingSetter { set { _ignoreOnSerializing = value; } } [JsonIgnore] private string _ignoreOnSerializing; [JsonIgnore] public string IgnoreOnSerializing { get { return this._ignoreOnSerializing; } set { this._ignoreOnSerializing = value; } }
希望这个帮助。
参考@ ThoHo的解决scheme,使用setter实际上是所有需要的,没有额外的标签。
对于我来说,我以前有一个参考ID,我想加载并添加到新的参考ID集合。 通过更改引用标识的定义来仅包含一个setter方法,该方法将值添加到新集合中。 如果属性没有get, Json就不能写回值; 方法。
// Old property that I want to read from Json, but never write again. No getter. public Guid RefId { set { RefIds.Add(value); } } // New property that will be in use from now on. Both setter and getter. public ICollection<Guid> RefIds { get; set; }
这个类现在向后兼容以前的版本,只保存新版本的RefIds 。
根据何's的回答,这也可以用于田野。
[JsonProperty(nameof(IgnoreOnSerializing))] public string IgnoreOnSerializingSetter { set { IgnoreOnSerializing = value; } } [JsonIgnore] public string IgnoreOnSerializing;