使用json.net使属性反序列化但不序列化

Wil*_*ean 104 c# json.net

我们有一些配置文件是通过使用Json.net序列化C#对象生成的.

我们希望将序列化类的一个属性从简单的枚举属性迁移到类属性.

一个简单的方法是将旧的enum属性保留在类上,并在我们加载配置时安排Json.net读取此属性,但是当我们下次序列化对象时不要再次保存它.我们将分别从旧枚举中处理生成新类.

是否有任何简单的方法来标记(例如,使用属性)C#对象的属性,以便Json.net仅在序列化时忽略它,但在反序列化时要注意它?

Bri*_*ers 109

实际上有几种相当简单的方法可用于实现您想要的结果.

例如,让我们假设您的类目前定义如下:

class Config
{
    public Fizz ObsoleteSetting { get; set; }
    public Bang ReplacementSetting { get; set; }
}

enum Fizz { Alpha, Beta, Gamma }

class Bang
{
    public string Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

你想这样做:

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);
Run Code Online (Sandbox Code Playgroud)

要得到这个:

{"ReplacementSetting":{"Value":"Gamma"}}
Run Code Online (Sandbox Code Playgroud)

方法1:添加ShouldSerialize方法

Json.NET能够通过ShouldSerialize在类中查找相应的方法来有条件地序列化属性.

要使用此功能,ShouldSerializeBlah()请在类中添加一个布尔方法,其中Blah替换为您不想序列化的属性的名称.使该方法的实现始终返回false.

class Config
{
    public Fizz ObsoleteSetting { get; set; }

    public Bang ReplacementSetting { get; set; }

    public bool ShouldSerializeObsoleteSetting()
    {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:如果您喜欢这种方法,但是您不想通过引入ShouldSerialize方法来混淆类的公共接口,则可以使用a IContractResolver以编程方式执行相同的操作.请参阅文档中的条件属性序列化.

方法2:使用JObjects操纵JSON

而不是使用JsonConvert.SerializeObject进行序列化,将配置对象加载到a中JObject,然后在写出之前简单地从JSON中删除不需要的属性.这只是几行代码.

JObject jo = JObject.FromObject(config);

// remove the "ObsoleteSetting" JProperty from its parent
jo["ObsoleteSetting"].Parent.Remove();

json = jo.ToString();
Run Code Online (Sandbox Code Playgroud)

方法3:聪明(ab)使用属性

  1. [JsonIgnore]属性应用于您不希望序列化的属性.
  2. 向类中添加备用私有属性setter,其类型与原始属性相同.使该属性的实现设置为原始属性.
  3. [JsonProperty]属性应用于备用setter,为其提供与原始属性相同的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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 我们通过将get-properties设置为internal来在我们的项目中解决它(它使用基本模型的内部集成特定超集,其中不应序列化任何超类属性).拥有公共setter允许Web Api设置属性,但阻止它序列化它们. (6认同)
  • 结合使用来自C#6.0的`JsonPropertyAttribute`,您可以使用`nameof`关键字而不是使用"魔术字符串".这使得重构*很多*更容易和万无一失 - 而且,如果你错过重命名任何事件,编译器将警告你,无论如何.使用@Brian的例子,用法是:`[JsonProperty(nameof(ObsoleteSetting))]` (6认同)
  • 在 JsonProperty 声明中使用 nameof() 是一个坏主意,特别是在这种遗留场景中。JSON 表示与另一个接口的外部(希望是永恒的)契约,如果重构,您绝对不想更改 JSON 属性的名称。您将破坏所有现有 JSON 文件和以此格式生成 JSON 的组件的兼容性。事实上,您最好将 JsonProperty(...) 与每个序列化属性的全名放在一起,以确保以后重命名属性时它们不会更改。 (3认同)

Iuc*_*unu 27

对于任何可以将仅反序列化属性标记为内部的情况,有一个非常简单的解决方案,完全不依赖于属性.只需将属性标记为内部get,但公共集:

public class JsonTest {

    public string SomeProperty { internal get; set; }

}
Run Code Online (Sandbox Code Playgroud)

这会导致使用默认设置/解析器/等正确反序列化,但该属性将从序列化输出中删除.

  • 这不适用于“内部”或“私有”。它总是序列化的。 (4认同)
  • 我忍不住想知道最后两个评论者是否将内部访问修饰符放在了 setter 而不是 getter 上。这与我使用 Json.NET 时所宣传的完全一样。也许 System.Text.Json 的工作方式有所不同。 (2认同)

Jra*_*o11 26

我喜欢在这个上坚持使用属性,这是我在需要反序列化属性但不对其进行序列化时使用的方法,反之亦然.

第1步 - 创建自定义属性

public class JsonIgnoreSerializationAttribute : Attribute { }
Run Code Online (Sandbox Code Playgroud)

第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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

步骤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
Run Code Online (Sandbox Code Playgroud)

第4步 - 使用它

var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!另外值得注意的是,当反序列化发生时,这也将忽略属性,当我进行derserializing时,我只是以传统方式使用转换器.

JsonConvert.DeserializeObject<MyType>(myString);
Run Code Online (Sandbox Code Playgroud)

  • 没关系,只是意识到它很简单:`return base.GetSerializableMembers(objectType).Where(pi =>!Attribute.IsDefined(pi,typeof(JsonIgnoreSerializationAttribute))).ToList();` (4认同)
  • 没关系,这实际上并没有满足提问者的要求。这基本上是重新创建 JsonIgnore。它不会跳过序列化属性,而是在反序列化期间设置属性,因为 GetSerializableMembers 方法无法知道它是读取还是写入,因此您排除了两者的属性。此解决方案不起作用。 (2认同)

小智 7

使用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; }
}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助.


小智 5

在我花了很长时间搜索如何将类属性标记为De-Serializable和NOT Serializable之后,我发现根本就没有这样做的事情; 所以我提出了一个结合了两种不同库或序列化技术的解决方案(System.Runtime.Serialization.Json和Newtonsoft.Json),它对我有用,如下所示:

  • 将所有类和子类标记为"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 });
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

希望有帮助......