17

NewtonsoftJSON.NETを使用するように古い作業を変換しようとしています。メソッドを使用したデフォルトの処理(たとえば、ターゲットタイプが指定されていない場合)は、内部オブジェクトSystem.Web.Script.Serialization.JavaScriptSerializer.Deserializeのを返すことです。Dictionary<string,object>

ExpandoObjectsこれは、JSONの基本的な型であり、動的型の最も賢明な内部実装であるため、実際には非常に便利な基本型です。

このタイプを指定した場合、例:

 var dict = JsonConvert.DeserializeObject<Dictionary<string,object>>(json);

JSON.NETは、最も外側のオブジェクト構造を正しく逆シリアル化しますが、JObject内部構造の型を返します。私が本当に必要としているのは、同じ外部構造を内部オブジェクトタイプの構造に使用することです。

返される最も外側のタイプだけでなく、内部オブジェクトに使用されるタイプを指定する方法はありますか?

4

2 に答える 2

27

Json.Netでjson文字列を逆シリアル化して、ネストされたオブジェクトと配列を逆シリアル化することを含めるには、Json.Netによって提供される抽象クラスIDictionary<string, object>から派生するカスタムクラスを作成する必要があります。JsonConverter

JsonConverterオブジェクトがjsonとの間でどのように書き込まれるべきかについての実装を配置するのは、派生物の中にあります。

JsonConverter次のようにカスタムを使用できます。

var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter());

これは、質問で概説したのと同じ目標を達成するために過去に成功して使用したカスタムJsonConverterです。

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

    private void WriteValue(JsonWriter writer, object value) {
        var t = JToken.FromObject(value);
        switch (t.Type) {
            case JTokenType.Object:
                this.WriteObject(writer, value);
                break;
            case JTokenType.Array:
                this.WriteArray(writer, value);
                break;
            default:
                writer.WriteValue(value);
                break;
        }
    }

    private void WriteObject(JsonWriter writer, object value) {
        writer.WriteStartObject();
        var obj = value as IDictionary<string, object>;
        foreach (var kvp in obj) {
            writer.WritePropertyName(kvp.Key);
            this.WriteValue(writer, kvp.Value);
        }
        writer.WriteEndObject();
    }

    private void WriteArray(JsonWriter writer, object value) {
        writer.WriteStartArray();
        var array = value as IEnumerable<object>;
        foreach (var o in array) {
            this.WriteValue(writer, o);
        }
        writer.WriteEndArray();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        return ReadValue(reader);
    }

    private object ReadValue(JsonReader reader) {
        while (reader.TokenType == JsonToken.Comment) {
            if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
        }

        switch (reader.TokenType) {
            case JsonToken.StartObject:
                return ReadObject(reader);
            case JsonToken.StartArray:
                return this.ReadArray(reader);
            case JsonToken.Integer:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Undefined:
            case JsonToken.Null:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return reader.Value;
            default:
                throw new JsonSerializationException
                    (string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
        }
    }

    private object ReadArray(JsonReader reader) {
        IList<object> list = new List<object>();

        while (reader.Read()) {
            switch (reader.TokenType) {
                case JsonToken.Comment:
                    break;
                default:
                    var v = ReadValue(reader);

                    list.Add(v);
                    break;
                case JsonToken.EndArray:
                    return list;
            }
        }

        throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
    }

    private object ReadObject(JsonReader reader) {
        var obj = new Dictionary<string, object>();

        while (reader.Read()) {
            switch (reader.TokenType) {
                case JsonToken.PropertyName:
                    var propertyName = reader.Value.ToString();

                    if (!reader.Read()) {
                        throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
                    }

                    var v = ReadValue(reader);

                    obj[propertyName] = v;
                    break;
                case JsonToken.Comment:
                    break;
                case JsonToken.EndObject:
                    return obj;
            }
        }

        throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
    }

    public override bool CanConvert(Type objectType) { return typeof(IDictionary<string, object>).IsAssignableFrom(objectType); }
}
于 2015-07-06T16:04:42.730 に答える
5

Jsonを使用して複雑なオブジェクトを逆シリアル化する場合は、パラメーターとしてJsonSerializer設定を追加する必要があります。これにより、すべての内部タイプが適切に逆シリアル化されます。

    private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All,
        TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
    };

オブジェクトをシリアル化するときは、SerializerSettingsを使用できます。

    string json= JsonConvert.SerializeObject(myObject, _jsonSettings)

次に、逆シリアル化するときに、次を使用します。

    var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, _jsonSettings);

また、シリアル化するときに、JsonSerializerSettingsをSerializeObject(object、settings)に追加します

編集:必要に応じて、TypeNameHandlingとTypeNameAssemblyFormatを変更することもできます。複雑なオブジェクトが間違いなく正しくシリアル化および逆シリアル化されるように、それぞれ「すべて」と「完全」に設定していますが、インテリセンスは他の選択肢を提供します

于 2012-08-01T14:45:39.850 に答える