web-dev-qa-db-ja.com

列挙型としてjson文字を逆シリアル化

次のように、C#で定義された列挙型があり、その値を文字として格納しています。

public enum CardType
{
    Artist = 'A',
    Contemporary = 'C',
    Historical = 'H',
    Musician = 'M',
    Sports = 'S',
    Writer = 'W'
}

JSON.NETを使用して逆シリアル化を試みていますが、次のように、着信JSONは列挙型のint値の代わりにCHAR値(文字列)を使用して記述されています。

[{"CardType","A"},{"CardType", "C"}]

文字を列挙値に手動で解析できるようにするコンバーターの種類を定義することは可能ですか?

私はJsonConverterを作成しようとしましたが、それをこのプロパティにのみ適用し、解析されたオブジェクト全体には適用しませんが、その方法はわかりません。これが私が試したものです:

public class EnumerationConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }

        int value = serializer.Deserialize<int>(reader);
        return (CardType)value;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsSubclassOf(typeof(string));
    }
}

ロジックが間違っている可能性があり、私はそれを修正できますが、問題はReadJson()がまったく呼び出されていないことです。

CanConvertはですが、私が定義した1つのプロパティだけでなく、すべてのプロパティに対して呼び出されるようです。

public class Card
{
            private CardType type;
        [JsonConverter(typeof(EnumerationConverter))]
        public CardType Type
        {
            get { return type; }
            set { type = value; }
        }
}

私はこれを間違って行ったと確信していますが、単一のフィールドに対してこれを行う方法に関するドキュメントを見つけるのに苦労しています...

何が欠けていますか?

25
SelAromDotNet

カスタムJsonConverterは必要ありません。組み込みStringEnumConverterEnumMemberAttribute の組み合わせで使用できます(System.Runtime.Serializationアセンブリ)。

EnumMemberAttributeがないと、列挙名が使用されるため、Artist、Contemporaryなどの名前をA、Cなどの値に変更する必要があります。

しかし、値を2回繰り返す必要があるため、これは最も良い解決策ではありませんが、機能します。

[JsonConverter(typeof(StringEnumConverter))]
public enum CardType
{
    [EnumMember(Value = "A")]
    Artist = 'A',
    [EnumMember(Value = "C")]
    Contemporary = 'C',
    [EnumMember(Value = "H")]
    Historical = 'H',
    [EnumMember(Value = "M")]
    Musician = 'M',
    [EnumMember(Value = "S")]
    Sports = 'S',
    [EnumMember(Value = "W")]
    Writer = 'W'
}
37
nemesv

このコードは完全に機能します:

CardType[] array = { CardType.Artist, CardType.Contemporary };
string s = JsonConvert.SerializeObject(array);
var array2 = JsonConvert.DeserializeObject<CardType[]>(s);

更新
標準のStringEnumConverterについて:

[JsonConverter(typeof(StringEnumConverter))]
public CardType Type { get; set; }
6
Vladimir

SerializerSettings.Converters.Add(new StringEnumConverter());を追加するだけです。

browserJsonFormatterクラスに

public class BrowserJsonFormatter : JsonMediaTypeFormatter
{
    public BrowserJsonFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
        SerializerSettings.Formatting = Formatting.Indented;
        SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        SerializerSettings.Converters.Add(new EmptyToNullConverter());
        SerializerSettings.Converters.Add(new StringEnumConverter());
        //SerializerSettings.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
    }

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
    {
        base.SetDefaultContentHeaders(type, headers, mediaType);
        headers.ContentType = new MediaTypeHeaderValue("application/json");
    }
}
1