Json.NET - CustomCreationConverter中单个属性的默认反序列化行为

时间:2014-02-03 21:16:15

标签: c# json json.net deserialization

在下面的场景中,当遇到我反序列化的类型中存在的JSON属性时,如何让CrazyItemConverter像往常一样继续进行?

我有一些看起来像这样的JSON:

{
    "Item":{
        "Name":"Apple",
        "Id":null,
        "Size":5,
        "Quality":2
    }
}

JSON被反序列化为一个看起来像这样的类:

[JsonConverter(typeof(CrazyItemConverter))]
public class Item
{
    [JsonConverter(typeof(CrazyStringConverter))]
    public string Name { get; set; }

    public Guid? Id { get; set; }

    [JsonIgnore]
    public Dictionary<string, object> CustomFields
    {
        get
        {
            if (_customFields == null)
                _customFields = new Dictionary<string, object>();
            return _customFields;
        }
    }

    ...
}

CrazyItemConverter填充已知属性的值,并将未知属性放入CustomFields中。其中的ReadJson如下所示:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var outputObject = Create(objectType);
    var objProps = objectType.GetProperties().Select(p => p.Name).ToArray();

    while (reader.Read())
    {
        if (reader.TokenType == JsonToken.PropertyName)
        {
            string propertyName = reader.Value.ToString();
            if (reader.Read())
            {
                if (objProps.Contains(propertyName))
                {
                    // No idea :(
                    // serializer.Populate(reader, outputObject);
                }
                else
                {
                    outputObject.AddProperty(propertyName, reader.Value);
                }
            }
        }
    }
    return outputObject;
}

在反序列化期间,当CrazyItemConverter遇到已知属性时,我希望它按照正常情况运行。含义,尊重[JsonConverter(typeof(CrazyStringConverter))]的{​​{1}}。

使用下面的代码来设置已知属性但是,它会抛出nullables上的异常并且不尊重我的其他JsonConverters。

Name

有什么想法吗?

更新:我已经了解到PropertyInfo pi = outputObject.GetType().GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType); pi.SetValue(outputObject, convertedValue, null); 是如何反序列化整个事情但是如果你想要逐个属性的默认功能它似乎不起作用

1 个答案:

答案 0 :(得分:8)

如果我正确理解,您的CrazyItemConverter存在,以便您可以将JSON中的已知属性反序列化为强类型属性,同时仍然保留可能在JSON中的“额外”字段到字典中。 / p>

事实证明,Json.Net已经内置了此功能(自5.0版本5开始),因此您不需要疯狂的转换器。相反,您只需要使用[JsonExtensionData]属性标记字典。 (有关详细信息,请参阅the author's blog。)

所以你的Item类看起来像这样:

public class Item
{
    [JsonConverter(typeof(CrazyStringConverter))]
    public string Name { get; set; }

    public Guid? Id { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> CustomFields
    {
        get
        {
            if (_customFields == null)
                _customFields = new Dictionary<string, object>();
            return _customFields;
        }
        private set
        {
            _customFields = value;
        }
    }
    private Dictionary<string, object> _customFields;
}

然后您可以正常反序列化它。演示:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""Item"":
            {
                ""Name"":""Apple"",
                ""Id"":""4b7e9f9f-7a30-4f79-8e47-8b50ea26ddac"",
                ""Size"":5,
                ""Quality"":2
            }
        }";

        Item item = JsonConvert.DeserializeObject<Wrapper>(json).Item;
        Console.WriteLine("Name: " + item.Name);
        Console.WriteLine("Id: " + item.Id);
        foreach (KeyValuePair<string, object> kvp in item.CustomFields)
        {
            Console.WriteLine(kvp.Key + ": " + kvp.Value);
        }
    }
}

public class Wrapper
{
    public Item Item { get; set; }
}

class CrazyStringConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        // Reverse the string just for fun
        return new string(token.ToString().Reverse().ToArray());
    }

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

输出:

Name: elppA
Id: 4b7e9f9f-7a30-4f79-8e47-8b50ea26ddac
Size: 5
Quality: 2