hoge

いわゆるWeb Developerの備忘録

【C#】JSONファイルをValueObjectまでデシリアライズする方法

.Net の System.Runtime.Serialization を使った json データからのデシリアライズで、ドメイン駆動設計の ValueObject を表現するのに苦労したので知見も兼ねて記事にしておこうと思います。

まず、以下のような形で json データが存在するとします。

{
  "user": {
    "id": 1,
    "type": 2
  }
}

これを単純に DataContract を使って、デシリアライズする場合は以下のようになります。

[DataContract]
public class User {
  [DataMember(Name = "id")]
  public int Id { get; }

  [DataMember(Name = "type")]
  public int Type { get; }
}

これはドメイン駆動設計でもなくただのデシリアライズですが、Typeは権限を表していて、値ごとに管理者や一般であると表示するようとすると、モデルに処理を集約したくなります(上記の場合モデル以外で変換の処理が必要になる)。

[DataContract]
public class User {
  [DataMember(Name = "id")]
  public int Id { get; }

  [DataMember(Name = "type")]
  public Type Type { get; }
}

public class Type {
  public static readonly AdminUser = new Type(1);
  public static readonly GeneralUser = new Type(2);

  public int Value { get; };
  public Type(int value) {
    this.Value = value
  }
  public string DisplayValue {
    get {
      switch (this.Value)
      {
        case: 1
          return "管理者";
        case: 2
          return "一般"
        default:
          return "一般"
      }
    }
  }
}

そう考えると上記の様な ValueObject が欲しいのですが、次の方法ではデシリアライズに失敗します。

[DataContract]
public class User {
  [DataMember(Name = "id")]
  public int Id { get; }

  [DataMember(Name = "type")]
  public Type Type { get; }
}

System.Runtime.Serialization ではユーザ定義のクラスはコンストラクタが呼べないので、使えないようです。

そのため、以下の方法でどうにかコンストラクタを呼ぶようにします。

[DataContract]
public class User {
  [DataMember(Name = "id")]
  public int Id { get; }

  [DataMember(Name = "type")]
  private int _TypeValue;
  public readonly Type Type {
    get {
      return new Type(_TypeValue);
    }
  }
}

このようにすることで、デシリアライズで呼ばれるときは int 型に代入しますが、privateなので外部からは見えなくなります。

実際に使いたいインスタンスはreadonlyで変更不可にして呼び出しています。

応急処置としては良いと思いますが、getter でインスタンスをnewするのはどうなんだろうと考えものです。

上記以外でいい解決方法があればいいのですが......


同じカテゴリー(Tech)の記事
上の画像に書かれている文字を入力して下さい
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

削除
【C#】JSONファイルをValueObjectまでデシリアライズする方法
    コメント(0)