7

この質問のstackoverflowには他にもいくつかの結果があることに気付きましたが、それらは機能していないようであるか、あいまいです。最も人気のある結果を使用して、これをまとめました。

問題は、JSON が戻ってきて、カスタム型の 1 つにシリアル化されているときに、JSON のビットの 1 つが配列である場合もあれば、単なる文字列である場合もあるということです。カスタム型に文字列があり、JSON が配列の場合、エラーが発生します。JSON がオブジェクトで、カスタム型が配列の場合、同じことが逆に起こります。それをプロパティにマップすることはできません。

私はこれを解決することにしました。この特定のプロパティの逆シリアル化をオーバーライドしたいと思います。オブジェクトの場合は、1 つのオブジェクトの配列に変換したいと考えています。

シリアル化するオブジェクトに、逆シリアル化の方法をオーバーライドすると思われる JsonConverter を追加しました。

[JsonConverter(typeof(ArrayOrSingleObjectConverter<string>))]
public List<string> person { get; set; }

アイデアは、カスタム コンバーターが単一のオブジェクトを配列に変換するというものです。したがって、JSON が「Hello」の場合、文字列をリストに変換できないという例外をスローする代わりに、「Hello」を含むリストに person を設定します。

すでに配列である場合は、そのままにしておく必要があります。

コンバーターは次のようになります。

public class ArrayOrSingleObjectConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true; // Not sure about this but technically it can accept an array or an object, so everything is game.
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (objectType == typeof(List<T>))
        {
            return serializer.Deserialize<List<T>>(reader);
        }
        else
        {
            var singleObject = serializer.Deserialize<T>(reader);
            var objectAsList = new List<T>();
            objectAsList.Add(singleObject);
            return objectAsList;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

うまくいきません。上記のコードは、単一の文字列を逆シリアル化しようとして、if ステートメント内でリストにキャストできないことを示す例外をスローします (ただし、「objecttype」はリストです)。

読み取りメソッドと書き込みメソッドが何をしているのかを正確に理解するのに苦労しています。stackoverflow に関する他の回答でNotImplementedExceptionは、読み取りメソッドで a をスローすることを提案しています。しかし、そうすると、read メソッドが呼び出され、例外がスローされます。

私は正しい道を進んでいると思いますが、正しい方向への微調整が必​​要です。ReadJSon メソッドが何をしているか、およびそのパラメーターが何を意味するかについて、少し混乱していると思います。

Deserialize メソッドの呼び出しで値を指定しなかったため、逆シリアル化されている値がどこから来ているのかよくわかりません。

私はこれについて私の深さから少し外れています。

4

2 に答える 2

9

私は先週似たようなことをしなければなりませんでしたが、配列ではなくリストに対してうまく機能する次のことを思いつきました

 internal class GenericListCreationJsonConverter<T> : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return true;
    }

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

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            return serializer.Deserialize<List<T>>(reader);
        }
        else
        {
            T t = serializer.Deserialize<T>(reader);
            return new List<T>(new[] { t });
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
于 2013-05-09T07:23:10.260 に答える
3

私は、Json.NET にすべての面倒な作業を行わせるこの方法が気に入っています。その結果、Json.NET がサポートするすべてのもの (List<>、ArrayList、厳密に型指定された配列など) がサポートされます。

public class FlexibleCollectionConverter : 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.StartArray)
        {
            return serializer.Deserialize(reader, objectType);
        }

        var array = new JArray(JToken.ReadFrom(reader));
        return array.ToObject(objectType);
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof (IEnumerable).IsAssignableFrom(objectType);
    }
}
于 2013-12-17T20:00:07.710 に答える