2

私はjson.netのドキュメントをかなりよく読んでいますが、アイデアが不足しています。私には、そこの両親に言及している子供がいる状況があります。そう

public class ObjA
{
  public int Id {get;set}
  public string OtherStuff {get;set}
  public ObjB MyChild {get;set}
}

public class ObjB
{
  public int Id {get;set}
  public string OtherStuff {get;set}
  public ObjA MyParent {get;set}
}

これはシリアライズしません。したがって、[JsonIgnore] を実行することもできますが、[JsonIdOnly] を実行したいのですが、ObjB では、MyParent をシリアル化したり、MyParent を完全にスキップしたりする代わりに、MyParentId:123 の json プロパティを表示します。そう

{OjbA:{
    Id:123,
    OtherStuff:some other stuff,
    MyChild:{
        Id:456,
        OtherStuff:Some other stuff,
        MyParentId:123,
        }
    }
 }

型のカスタム コンバーターを作成できることはわかっています。問題は、指定された場合にのみこれが発生するようにしたいということです。そうしないと、ObjA をシリアル化できないからです。つまり、属性で装飾した場合にのみこれが発生する必要があります。そう

public class ObjB
{
  public int Id {get;set}
  public string OtherStuff {get;set}
  [JsonIdOnly]
  public ObjA MyParent {get;set}
}
4

2 に答える 2

2

JSON に余分な簿記情報が含まれていることを気にしない場合は、@Athari が提案したように、PreserveReferenceHandlingオプションJsonSerializerSettingsAll(または) に設定します。Objectsそれが最も簡単な方法です。これを行うと、JSON は次のようになります。

{
  "$id": "1",
  "Id": 123,
  "OtherStuff": "other stuff A",
  "MyChild": {
    "$id": "2",
    "Id": 456,
    "OtherStuff": "other stuff B",
    "MyParent": {
      "$ref": "1"
    }
  }
}

そうは言っても、 custom を使用して、元々望んでいたことを行う方法がありますJsonConverter。できることは、Id プロパティを持つ任意のオブジェクトを受け入れるコンバーターを作成することです。次に、ID としてのみシリアル化する必要がある場所では、それらのプロパティを[JsonConverter]属性で装飾できます。カスタム コンバーターはそのような場合に使用されますが、それ以外の場合には使用されません。コンバーターは次のようになります。

class IdOnlyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsClass;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        writer.WritePropertyName("Id");
        writer.WriteValue(GetId(value));
        writer.WriteEndObject();
    }

    private int GetId(object obj)
    {
        PropertyInfo prop = obj.GetType().GetProperty("Id", typeof(int));
        if (prop != null && prop.CanRead)
        {
            return (int)prop.GetValue(obj, null);
        }
        return 0;
    }

    public override bool CanRead 
    { 
        get { return false; } 
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

コンバーターを使用するには、概説したようにクラスを設定します。Json.NetMyParentにそのプロパティのカスタム コンバーターを使用するように指示する属性で装飾されていることに注目してください。

public class ObjA
{
    public int Id { get; set; }
    public string OtherStuff { get; set; }
    public ObjB MyChild { get; set; }
}

public class ObjB
{
    public int Id { get; set; }
    public string OtherStuff { get; set; }
    [JsonConverter(typeof(IdOnlyConverter))]
    public ObjA MyParent { get; set; }
}

シリアル化するときは、toのReferenceLoopHandlingオプションを設定して、参照ループが検出された場合にエラーをスローしないように Json.Net に指示し、とにかくシリアル化を続行する必要があります (コンバーターがそれを処理するため)。JsonSerializerSettingsSerialize

すべてをまとめると、コンバーターの動作を示すコード例がいくつかあります。

class Program
{
    static void Main(string[] args)
    {
        ObjA a = new ObjA();
        a.Id = 123;
        a.OtherStuff = "other stuff A";

        ObjB b = new ObjB();
        b.Id = 456;
        b.OtherStuff = "other stuff B";
        b.MyParent = a;

        a.MyChild = b;

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
            Formatting = Newtonsoft.Json.Formatting.Indented
        };

        string json = JsonConvert.SerializeObject(a, settings);
        Console.WriteLine(json);
    }
}

そして、これが上記の出力です:

{
  "Id": 123,
  "OtherStuff": "other stuff A",
  "MyChild": {
    "Id": 456,
    "OtherStuff": "other stuff B",
    "MyParent": {
      "Id": 123
    }
  }
}
于 2013-10-03T17:28:15.673 に答える