web-dev-qa-db-ja.com

特定の型をシリアル化するときにJSON.NetシリアライザーがToString()を呼び出すようにする方法は?

Newtonsoft.Jsonシリアライザーを使用してC#クラスをJSONに変換しています。一部のクラスでは、個々のプロパティへのインスタンスへのシリアライザーは必要ありませんが、代わりにオブジェクトでToStringを呼び出すだけです。

public class Person
{
   public string FirstName { get; set; }
   public string LastName { get; set; }

   public override string ToString() { return string.Format("{0} {1}", FirstName, LastName ); }
}

ToString()メソッドの結果としてPersonオブジェクトをシリアル化するにはどうすればよいですか?私はこのような多くのクラスを持っている可能性があるので、Personクラスに固有のシリアライザーで終わるのではなく、(私が推測する属性を介して)どのクラスにも適用できるシリアライザーを用意したいと思います。

24
Vagif Abilov

カスタム JsonConverter でこれを簡単に行うことができます:

_public class ToStringJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

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

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

コンバーターを使用するには、次のように_[JsonConverter]_属性を使用して文字列としてシリアル化する必要があるクラスを装飾します。

_[JsonConverter(typeof(ToStringJsonConverter))]
public class Person
{
    ...
}
_

以下は、コンバーターの動作を示すデモです。

_class Program
{
    static void Main(string[] args)
    {
        Company company = new Company
        {
            CompanyName = "Initrode",
            Boss = new Person { FirstName = "Head", LastName = "Honcho" },
            Employees = new List<Person>
            {
                new Person { FirstName = "Joe", LastName = "Schmoe" },
                new Person { FirstName = "John", LastName = "Doe" }
            }
        };

        string json = JsonConvert.SerializeObject(company, Formatting.Indented);
        Console.WriteLine(json);
    }
}

public class Company
{
    public string CompanyName { get; set; }
    public Person Boss { get; set; }
    public List<Person> Employees { get; set; }
}

[JsonConverter(typeof(ToStringJsonConverter))]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public override string ToString() 
    { 
        return string.Format("{0} {1}", FirstName, LastName); 
    }
}
_

出力:

_{
  "CompanyName": "Initrode",
  "Boss": "Head Honcho",
  "Employees": [
    "Joe Schmoe",
    "John Doe"
  ]
}
_

文字列からオブジェクトに変換する必要がある場合は、public static Parse(string)メソッドを探して呼び出すように、コンバーターにReadJsonメソッドを実装できます。注:コンバータのCanReadメソッドを変更してtrueを返すようにしてください(またはCanReadオーバーロードを完全に削除してください)。そうしないと、ReadJsonが呼び出されることはありません。

_public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    MethodInfo parse = objectType.GetMethod("Parse", new Type[] { typeof(string) });
    if (parse != null && parse.IsStatic && parse.ReturnType == objectType)
    {
        return parse.Invoke(null, new object[] { (string)reader.Value });
    }

    throw new JsonException(string.Format(
        "The {0} type does not have a public static Parse(string) method that returns a {0}.", 
        objectType.Name));
}
_

もちろん、上記が機能するためには、変換する各クラスに適切なParseメソッドが実装されていることを確認する必要があります(まだ存在しない場合)。上記のPersonクラスの例では、そのメソッドは次のようになります。

_public static Person Parse(string s)
{
    if (string.IsNullOrWhiteSpace(s))
        throw new ArgumentException("s cannot be null or empty", "s");

    string[] parts = s.Split(new char[] { ' ' }, 2);
    Person p = new Person { FirstName = parts[0] };
    if (parts.Length > 1)
        p.LastName = parts[1];

    return p;
}
_

往復デモ: https://dotnetfiddle.net/fd4EG4

48
Brian Rogers

大規模での使用を目的としていない場合は、これを行うより速い方法があります。以下の例では、RecordTypeプロパティ

[JsonIgnore]
public RecordType RecType { get; set; }

[JsonProperty(PropertyName = "RecordType")]
private string RecordTypeString => RecType.ToString();
8
Ismail Hawayel

Newtonsoft JSONビルダーライブラリを試し、次のコードを使用してタイプPersonのオブジェクトをシリアル化できます。

Dictionary<string, object> collection = new Dictionary<string, object>()
    {
      {"First", new Person(<add FirstName as constructor>)},
      {"Second", new Person(<add LastName as constructor>)},

    };
string json = JsonConvert.SerializeObject(collection, Formatting.Indented, new JsonSerializerSettings
  {
    TypeNameHandling = TypeNameHandling.All,
    TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
  });
0
Abhishek Dey