如何使用Json.Net将Dictionary序列化为其父对象的一部分

Nat*_*aly 35 c# serialization json.net

我正在使用Json.Net进行序列化.我有一个带有词典的类:

public class Test
{
    public string X { get; set; }

    public Dictionary<string, string> Y { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我可以以某种方式序列化此对象以获取以下JSON

{
    "X" : "value",
    "key1": "value1",
    "key2": "value2"
}
Run Code Online (Sandbox Code Playgroud)

其中"key1","key2"是字典中的键?

Bri*_*ers 49

如果您使用Json.Net 5.0.5或更高版本以及你愿意从改变你的字典的类型Dictionary<string, string>Dictionary<string, object>,然后一个简单的方法来完成你想要的是将添加[JsonExtensionData]属性您喜欢这本字典属性:

public class Test
{
    public string X { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> Y { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后,标记字典的键和值将被序列化为父对象的一部分.奖励是它也适用于反序列化:JSON中与类成员不匹配的任何属性都将放入字典中.

  • @ChristopheGigax 因为“JsonExtensionData”功能旨在捕获 JSON 中目标类中没有相应属性的所有内容。“任何东西”可能意味着数字、布尔值、数组或子对象,它们都不会进入“Dictionary&lt;string, string&gt;”。因此,即使您的 JSON 恰好只包含字符串值,您也必须使用 `Dictionary&lt;string, object&gt;` 或 `Dictionary&lt;string, JToken&gt;`。这就是它的工作原理。如果您想要其他东西,则需要使用自定义的“JsonConverter”。 (2认同)

Ser*_*nov 8

实现JsonConverter派生类:CustomCreationConverter类应该用作基类来创建自定义对象.

转换器的草稿版本(可以根据需要改进错误处理):

internal class TestObjectConverter : CustomCreationConverter<Test>
{
    #region Overrides of CustomCreationConverter<Test>

    public override Test Create(Type objectType)
    {
        return new Test
            {
                Y = new Dictionary<string, string>()
            };
    }

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

        // Write properties.
        var propertyInfos = value.GetType().GetProperties();
        foreach (var propertyInfo in propertyInfos)
        {
            // Skip the Y property.
            if (propertyInfo.Name == "Y")
                continue;

            writer.WritePropertyName(propertyInfo.Name);
            var propertyValue = propertyInfo.GetValue(value);
            serializer.Serialize(writer, propertyValue);
        }

        // Write dictionary key-value pairs.
        var test = (Test)value;
        foreach (var kvp in test.Y)
        {
            writer.WritePropertyName(kvp.Key);
            serializer.Serialize(writer, kvp.Value);
        }
        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jsonObject = JObject.Load(reader);
        var jsonProperties = jsonObject.Properties().ToList();
        var outputObject = Create(objectType);

        // Property name => property info dictionary (for fast lookup).
        var propertyNames = objectType.GetProperties().ToDictionary(pi => pi.Name, pi => pi);
        foreach (var jsonProperty in jsonProperties)
        {
            // If such property exists - use it.
            PropertyInfo targetProperty;
            if (propertyNames.TryGetValue(jsonProperty.Name, out targetProperty))
            {
                var propertyValue = jsonProperty.Value.ToObject(targetProperty.PropertyType);
                targetProperty.SetValue(outputObject, propertyValue, null);
            }
            else
            {
                // Otherwise - use the dictionary.
                outputObject.Y.Add(jsonProperty.Name, jsonProperty.Value.ToObject<string>());
            }
        }

        return outputObject;
    }

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

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

客户代码:

var test = new Test
    {
        X = "123",
        Y = new Dictionary<string, string>
            {
                { "key1", "value1" },
                { "key2", "value2" },
                { "key3", "value3" },
            }
    };

string json = JsonConvert.SerializeObject(test, Formatting.Indented, new TestObjectConverter());
var deserializedObject = JsonConvert.DeserializeObject<Test>(json);
Run Code Online (Sandbox Code Playgroud)

请注意:属性名称和字典的键名之间可能存在冲突.