読者です 読者をやめる 読者になる 読者になる

Json.NET - enumを文字列でシリアライズする

久しぶりにJson.NETのメモです。

Json.NETを使ってenum値をJSONに出力するとき、デフォルトでは数値になります。数値だとぱっと見わかりにくいので文字列で書き出したいときがあると思います。そんなときはStringEnumConverterを使います。

使い方はたぶん2通り。

  • プロパティなどに対してJsonConverterAttributeとセットで使う
  • JsonSerializerSettings.Convertersに加える

あるプロパティのenumだけを対象にしたい場合はJsonConverterAttribute、すべてのプロパティのenumを対象にしたい場合はJsonSerializerSettings.Convertersを使用するといった感じかなと思います。

enumを文字列でシリアライズ

どちらもコードで確認してみます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

namespace ConsoleApp {
    // 適当なenum
    enum LogLevel {
        None,
        Info,
        Warn,
        Error,
    }

    // 適当なサンプル
    class Logger {
        public string Name { get; set; }

        public LogLevel MinLevel { get; set; }

        // JsonConverterAttributeでStringEnumConverterを指定する
        [JsonConverter(typeof(StringEnumConverter))]
        public LogLevel MaxLevel { get; set; }
    }


    class Program {
        static void Main(string[] args) {
            var settings = new JsonSerializerSettings {
                // ついでにプロパティ名をキャメルケースで出力
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                // 見やすいようにインデントで整形
                Formatting = Formatting.Indented,
            };

            var logger = new Logger {
                Name = "test",
                MinLevel = LogLevel.Info,
                MaxLevel = LogLevel.Warn,
            };

            // シリアライズして属性で指定したmaxLevelの値が文字列になっていることを確認
            Console.WriteLine(JsonConvert.SerializeObject(logger, settings));
            /*
           {
             "name": "test",
             "minLevel": 1,
             "maxLevel": "Warn"
           }
           */

            // StringEnumConverterをConvertersに追加する
            // さらにenum文字列はキャメルケースに
            settings.Converters.Add(new StringEnumConverter { CamelCaseText = true });

            // シリアライズしてminLevelとmaxLevelの値が文字列になっていることを確認
            Console.WriteLine(JsonConvert.SerializeObject(logger, settings));
            /*
           {
             "name": "test",
             "minLevel": "info",
             "maxLevel": "Warn"
           }
           */
            // この場合、maxLevelの"Warn"はキャメルケースにならない
            // 属性のStringEnumConverterが優先される様子
            // (今回のサンプルのように2重で設定するような使い方はしないと思うが)
        }
    }
}

enumへデシリアライズ

enumへデシリアライズするときはJsonSerializerSettingsを使わなくても数値でも文字列でもいい感じに処理してくれます。

var json = @"
{
  ""name"":""test"",
  ""minLevel"":""info"",
  ""maxLevel"":2
}";
var logger = JsonConvert.DeserializeObject<Logger>(json);
Console.WriteLine(logger.Name); // test
Console.WriteLine(logger.MinLevel); // Info
Console.WriteLine(logger.MaxLevel); // Warn

参考