C# 使属性反序列化但不使用 json.net 序列化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11564091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Making a property deserialize but not serialize with json.net
提问by Will Dean
We have some configuration files which were generated by serializing C# objects with Json.net.
我们有一些配置文件是通过使用 Json.net 序列化 C# 对象生成的。
We'd like to migrate one property of the serialised class away from being a simple enum property into a class property.
我们希望将序列化类的一个属性从简单的枚举属性迁移到类属性。
One easy way to do this, would be to leave the old enum property on the class, and arrange for Json.net to read this property when we load the config, but not to save it again when we next serialize the object. We'll deal with generating the new class from the old enum separately.
一种简单的方法是将旧的枚举属性保留在类上,并安排 Json.net 在加载配置时读取此属性,但在下次序列化对象时不再保存它。我们将分别处理从旧枚举生成新类的问题。
Is there any simple way to mark (e.g. with attributes) a property of a C# object, so that Json.net will ignore it ONLY when serializing, but attend to it when deserializing?
是否有任何简单的方法来标记(例如,使用属性)C# 对象的属性,以便 Json.net 仅在序列化时忽略它,但在反序列化时注意它?
采纳答案by Brian Rogers
There are actually several fairly simple approaches you can use to achieve the result you want.
实际上,您可以使用几种相当简单的方法来实现您想要的结果。
Let's assume, for example, that you have your classes currently defined like this:
例如,让我们假设您的类当前定义如下:
class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
}
enum Fizz { Alpha, Beta, Gamma }
class Bang
{
public string Value { get; set; }
}
And you want to do this:
你想这样做:
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);
To get this:
要得到这个:
{"ReplacementSetting":{"Value":"Gamma"}}
Approach 1: Add a ShouldSerialize method
方法一:添加一个ShouldSerialize方法
Json.NET has the ability to conditionally serialize properties by looking for corresponding ShouldSerializemethods in the class.
Json.NET 能够通过ShouldSerialize在类中查找相应的方法来有条件地序列化属性。
To use this feature, add a boolean ShouldSerializeBlah()method to your class where Blahis replaced with the name of the property that you do not want to serialize. Make the implementation of this method always return false.
要使用此功能,请ShouldSerializeBlah()向您的类添加一个布尔方法,其中Blah替换为您不想序列化的属性的名称。使该方法的执行始终返回false。
class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
public bool ShouldSerializeObsoleteSetting()
{
return false;
}
}
Note: if you like this approach but you don't want to muddy up the public interface of your class by introducing a ShouldSerializemethod, you can use an IContractResolverto do the same thing programmatically. See Conditional Property Serializationin the documentation.
注意:如果您喜欢这种方法,但又不想通过引入ShouldSerialize方法来混淆类的公共接口,则可以使用 anIContractResolver以编程方式执行相同的操作。请参阅文档中的条件属性序列化。
Approach 2: Manipulate the JSON with JObjects
方法 2:使用 JObjects 操作 JSON
Instead of using JsonConvert.SerializeObjectto do the serialization, load the config object into a JObject, then simply remove the unwanted property from the JSON before writing it out. It's just a couple of extra lines of code.
不是JsonConvert.SerializeObject用来进行序列化,而是将配置对象加载到 a 中JObject,然后在写出之前简单地从 JSON 中删除不需要的属性。这只是几行额外的代码。
JObject jo = JObject.FromObject(config);
// remove the "ObsoleteSetting" JProperty from its parent
jo["ObsoleteSetting"].Parent.Remove();
json = jo.ToString();
Approach 3: Clever (ab)use of attributes
方法 3:巧妙 (ab) 使用属性
- Apply a
[JsonIgnore]attribute to the property that you do not want to be serialized. - Add an alternate, privateproperty setter to the class with the same type as the original property. Make the implementation of that property set the original property.
- Apply a
[JsonProperty]attribute to the alternate setter, giving it the same JSON name as the original property.
- 将
[JsonIgnore]特性应用到您不想被序列化的属性。 - 将备用的私有属性设置器添加到与原始属性具有相同类型的类。使该属性的实现设置为原始属性。
- 将
[JsonProperty]属性应用到备用 setter,为其提供与原始属性相同的 JSON 名称。
Here is the revised Configclass:
这是修改后的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; }
}
回答by Ahmed Abulazm
After i spent a quite long time searching how to flag a class property to be De-Serializable and NOT Serializable i found that there's no such thing to do that at all; so i came up with a solution that combines two different libraries or serialization techniques (System.Runtime.Serialization.Json & Newtonsoft.Json) and it worked for me like the following:
在我花了很长时间搜索如何将类属性标记为可反序列化和不可序列化之后,我发现根本没有这样的事情要做;所以我想出了一个解决方案,它结合了两个不同的库或序列化技术(System.Runtime.Serialization.Json 和 Newtonsoft.Json),它对我有用,如下所示:
- flag all your class and sub-classes as "DataContract".
- flag all the properties of your class and sub-classes as "DataMember".
- flag all the properties of your class and sub-classes as "JsonProperty" except those you want them not to be serialized.
- now flag the properties the you do NOT want it to be serialized as "JsonIgnore".
then Serialize using "Newtonsoft.Json.JsonConvert.SerializeObject" and De-Serialize using "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 }); } } }
- 将您的所有类和子类标记为“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 }); } } }
Hope that helps ...
希望有帮助...
回答by Tho Ho
Use setter property:
使用 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; }
}
Hope this help.
希望这有帮助。
回答by Jraco11
I like sticking with attributes on this one, here is the method I use when needing to deserialize a property but not serialize it or vice versa.
我喜欢坚持使用属性,这是我在需要反序列化属性但不序列化它时使用的方法,反之亦然。
STEP 1 - Create the custom attribute
步骤 1 - 创建自定义属性
public class JsonIgnoreSerializationAttribute : Attribute { }
STEP 2 - Create a custom Contract Reslover
第 2 步 - 创建自定义合同转接器
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>();
}
}
STEP 3 - Add attribute where serialization is not needed but deserialization is
第 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
STEP 4 - Use it
第 4 步 - 使用它
var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });
Hope this helps! Also it's worth noting that this will also ignore the properties when Deserialization happens, when I am derserializing I just use the converter in the conventional way.
希望这可以帮助!另外值得注意的是,当反序列化发生时,这也会忽略属性,当我反序列化时,我只是以传统方式使用转换器。
JsonConvert.DeserializeObject<MyType>(myString);
回答by simo.3792
with reference to @ThoHo's solution, using the setter is actually all that is needed, with no additional tags.
参考@ThoHo 的解决方案,实际上只需要使用 setter,无需其他标签。
For me I previously had a single reference Id, that I wanted to load and add to the new collection of reference Ids. By changing the definition of the reference Id to only contain a setter method, which added the value to the new collection. Json can't write the value back if the Property doesn't have a get;method.
对我来说,我以前有一个单一的参考 ID,我想加载它并将其添加到新的参考 ID 集合中。通过将引用 Id 的定义更改为仅包含一个 setter 方法,该方法将值添加到新集合中。如果 Property 没有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; }
This class is now backwards compatible with the previous version and only saves the RefIdsfor the new versions.
此类现在向后兼容以前的版本,并且只保存新版本的RefId。
回答by Bendik August Nesb?
To build upon Tho Ho's answer, this can also be used for fields.
为了建立在 Tho Ho 的回答之上,这也可以用于字段。
[JsonProperty(nameof(IgnoreOnSerializing))]
public string IgnoreOnSerializingSetter { set { IgnoreOnSerializing = value; } }
[JsonIgnore]
public string IgnoreOnSerializing;
回答by Iucounu
For any situation where it's acceptable to have your deserialization-only property be marked internal, there's a remarkably simple solution that doesn't depend on attributes at all. Simply mark the property as internal get, but public set:
对于将仅反序列化属性标记为内部是可以接受的任何情况,有一个非常简单的解决方案,它根本不依赖于属性。只需将属性标记为内部获取,但公共设置:
public class JsonTest {
public string SomeProperty { internal get; set; }
}
This results in correct deserialization using default settings/resolvers/etc., but the property is stripped from serialized output.
这会导致使用默认设置/解析器/等进行正确的反序列化,但该属性已从序列化输出中剥离。
回答by menxin
If you use JsonConvert,IgnoreDataMemberAttributeis ok.My standard library not refrence Newton.Json,and I use [IgnoreDataMember] to control object serialize.
如果你使用 JsonConvert,IgnoreDataMemberAttribute是可以的。我的标准库不引用 Newton.Json,我使用 [IgnoreDataMember] 来控制对象序列化。
From Newton.nethelp document.
来自Newton.net帮助文档。
回答by OzzyTheGiant
Depending on where in the application this takes place and if it's just one property, one manualway you can do this is by setting the property value to null and then on the model you can specify that the property be ignored if the value is null:
根据应用程序中发生的位置,如果它只是一个属性,您可以手动执行此操作的一种方法是将属性值设置为 null,然后在模型上指定如果值为 null,则忽略该属性:
[JsonProperty(NullValueHandling = NullValue.Ignore)]
public string MyProperty { get; set; }
If you are working on an ASP.NET Core web app, you can globally set this for all properties in all models by setting this in your Startup.cs file:
如果您正在处理 ASP.NET Core Web 应用程序,则可以通过在 Startup.cs 文件中进行设置来为所有模型中的所有属性全局设置此项:
public void ConfigureServices(IServiceCollection services) {
// other configuration here
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore);
}
回答by No Refunds No Returns
Is there any simple way to mark (e.g. with attributes) a property of a C# object, so that Json.net will ignore it ONLY when serializing, but attend to it when deserializing?
是否有任何简单的方法来标记(例如,使用属性)C# 对象的属性,以便 Json.net 仅在序列化时忽略它,但在反序列化时注意它?
The easiest way I've found as of this writing is to include this logic in your IContractResolver.
在撰写本文时,我发现的最简单方法是将此逻辑包含在您的IContractResolver 中。
Sample code from above link copied here for posterity:
上面链接中的示例代码复制到这里供后代使用:
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
// don't serialize the Manager property if an employee is their own manager
return (Manager != this);
}
}
public class ShouldSerializeContractResolver : DefaultContractResolver
{
public new static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(Employee) && property.PropertyName == "Manager")
{
property.ShouldSerialize =
instance =>
{
Employee e = (Employee)instance;
return e.Manager != e;
};
}
return property;
}
}
All of the answers are good but this approach seemed like the cleanest way. I actually implemented this by looking for an attribute on the property for SkipSerialize and SkipDeserialize so you can just mark up any class you control. Great question!
所有的答案都很好,但这种方法似乎是最干净的方法。我实际上是通过在属性上查找 SkipSerialize 和 SkipDeserialize 的属性来实现的,这样您就可以标记您控制的任何类。好问题!

