1

現在、プロジェクトで Json.Net シリアライザーを利用しようとしています。

私が最近直面した問題の 1 つは、デシリアライズされたオブジェクトがプライベート リスト アイテムをすべて複製することです。次のように再現できます。

  1. タイプprivateのフィールドを持つクラスを作成します。ここで、ジェネリック パラメーターは他のクラスですList<>List<>
  2. フィールドpublicを取得/設定するプロパティを追加private
  3. そのクラスのインスタンスを作成し、プロパティを使用して内部リストに 1 項目を追加します。
  4. プライベート クラス データを表示するように設定された新しい DefaultContractResolver でシリアル化します。
  5. 逆シリアル化

問題を再現するコード:

    public class ClassParam
    {
        public int? ParamOne
        {
            get;
            set;
        }
    }
    public class ClassWithParams
    {
        private List<ClassParam> _privateFieid = new List<ClassParam>();

        public List<ClassParam> PropertWithBackingField
        {
            get { return _privateFieid; }
            set { _privateFieid = value; }
        }
        
        public void AddElementToPrivateField(ClassParam classParam)
        {
            _privateFieid.Add(classParam);
        }
        
    }
    [Test]
    public void Test()
    {
            var instance = new ClassWithParams();

        var param1 = new ClassParam { ParamOne = 1 };

        instance.PropertWithBackingField.Add(param1);

        var contractResolver = new DefaultContractResolver();
        contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;

        string serializedInstance = JsonConvert.SerializeObject(instance,
                                                                   Formatting.Indented,
                                                                   new JsonSerializerSettings()
                                                                   {
                                                                       ContractResolver = contractResolver
                                                                      
                                                                   });

        var deserializeInstance = JsonConvert.DeserializeObject(serializedInstance, typeof(ClassWithParams),
                                                                         new JsonSerializerSettings()
                                                                         {
                                                                             ContractResolver = contractResolver
                                                                         });
    }

1

公共財産を削除すると、PropertWithBackingFieldすべてClassWithParams問題ありません。ContractResolver のカスタム セットアップを使用しない場合も、問題はなくなりました。しかし、クラスのプライベート データのすべてがパブリック プロパティを介して公開されていない場合は、すぐにシリアル化する必要があります。

コードの何が問題になっていますか? Json.Net を使用して微妙な点はありますか、それともバグですか?

4

2 に答える 2

1

このコードについて

var s = JsonConvert.SerializeObject(instance);
var desInst = JsonConvert.DeserializeObject<ClassWithParams>(s);

あなたのjsonは{"PropertWithBackingField":[{"ParamOne":1}]}

しかし、シリアライゼーション/デシリアライゼーションにプライベートフィールドを含めると言います

contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;

jsonを取得します

   {
  "_privateFieid": [
    {
      "ParamOne": 1
    }
  ],
  "PropertWithBackingField": [
    {
      "ParamOne": 1
    }
  ]
 }

したがって、2 つのデシリアライゼーションがあり、1 つは for_privateFieidと 1 つは for です。PropertWithBackingField

BindingFlags.Public上記のコードを使用するか、使用する方がはるかに簡単です。

于 2012-09-27T07:42:47.913 に答える
-2

DeserializeInstanceメソッドは既存のインスタンスを引数として受け取ります。おそらく、新しいインスタンスを作成するのではなく、既存のものを埋めて返します。

ReferenceEquals(instance, deserializedInstance)腕時計につけてみてください。データの重複を避けるには、既存のインスタンスを受け入れないオーバーロードを使用するか、新しいインスタンスを作成して逆シリアル化します。

于 2012-09-27T06:39:53.910 に答える