158

Json.net で C# オブジェクトをシリアル化することによって生成された構成ファイルがいくつかあります。

シリアル化されたクラスの 1 つのプロパティを単純な列挙型プロパティからクラス プロパティに移行したいと考えています。

これを行う簡単な方法の 1 つは、クラスに古い enum プロパティを残し、構成をロードするときに Json.net がこのプロパティを読み取るように手配し、次にオブジェクトをシリアル化するときに再度保存しないようにすることです。古い列挙型からの新しいクラスの生成については、個別に扱います。

Json.net がシリアライズ時にのみ無視し、デシリアライズ時に注意を払うように、C# オブジェクトのプロパティを (属性などで) マークする簡単な方法はありますか?

4

12 に答える 12

165

実際には、必要な結果を得るために使用できるかなり単純なアプローチがいくつかあります。

たとえば、クラスが現在次のように定義されているとします。

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 メソッドを追加する

ShouldSerializeJson.NET には、クラス内の対応するメソッドを 探すことによって、プロパティを条件付きでシリアル化する機能があります。

この機能を使用するには、ブール値ShouldSerializeBlah()メソッドをクラスに追加します。ここでBlah、シリアライズしたくないプロパティの名前に置き換えます。このメソッドの実装が常に を返すようにしfalseます。

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

    public Bang ReplacementSetting { get; set; }

    public bool ShouldSerializeObsoleteSetting()
    {
        return false;
    }
}

注: このアプローチが気に入っているが、ShouldSerializeメソッドを導入してクラスのパブリック インターフェイスを混乱させたくない場合は、 を使用しIContractResolverてプログラムで同じことを行うことができます。ドキュメントの条件付きプロパティのシリアル化を参照してください。

アプローチ 2: JObjects を使用して JSON を操作する

を使用してシリアル化を行う代わりにJsonConvert.SerializeObject、config オブジェクトを にロードしJObject、JSON から不要なプロパティを削除してから書き出すだけです。ほんの数行の追加コードです。

JObject jo = JObject.FromObject(config);

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

json = jo.ToString();

アプローチ 3: 属性の巧妙な (乱用) 使用

  1. [JsonIgnore]シリアライズしたくないプロパティに属性を適用します。
  2. 元のプロパティと同じタイプの代替のプライベートプロパティ セッターをクラスに追加します。そのプロパティの実装を元のプロパティに設定します。
  3. [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; }
}
于 2014-06-14T21:28:48.780 に答える
39

私はこの属性に固執するのが好きです。これは、プロパティを逆シリアル化する必要があるがシリアル化しない場合、またはその逆の場合に使用する方法です。

ステップ 1 - カスタム属性を作成する

public class JsonIgnoreSerializationAttribute : Attribute { }

ステップ 2 - カスタム コントラクト Reslover を作成する

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 - シリアル化は必要ないが逆シリアル化が必要な属性を追加する

    [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 - 使う

var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });

お役に立てれば!また、逆シリアル化が発生したときにプロパティも無視されることに注意してください。逆シリアル化するときは、従来の方法でコンバーターを使用するだけです。

JsonConvert.DeserializeObject<MyType>(myString);
于 2016-02-05T22:50:41.910 に答える
8

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; }
}

この助けを願っています。

于 2014-06-13T10:10:20.523 に答える
4

クラス プロパティに De-Serializable と NOT Serializable のフラグを付ける方法を探すのにかなりの時間を費やした後、それを行うようなことはまったくないことがわかりました。そこで、2 つの異なるライブラリまたはシリアル化手法 (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 });
            }
        }
    }
    

それが役立つことを願っています...

于 2013-04-02T18:58:51.957 に答える
0

Jraco11 の答えは非常にきちんとしています。場合によっては、シリアル化と逆シリアル化の両方に同じ IContractResolver を使用する場合は、次を使用できます。

public class JsonPropertiesResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (member.IsDefined(typeof(JsonIgnoreSerializationAttribute)))
        {
            property.ShouldSerialize = instance => false;
        }

        return property;
    }
}
于 2021-02-03T08:23:21.253 に答える