Json.NET不会在对象的列表或字典中保留原始类型信息。有解决方法吗?

时间:2014-07-29 01:40:21

标签: c# json json.net

以下示例说明了Json.NET类型处理的一个基本缺陷:

List<object> items = new List<object>() {Guid.NewGuid(),DateTime.Now};
var settings = new JsonSerializerSettings() { TypeNameHandling=TypeNameHandling.All };
var json = JsonConvert.SerializeObject<List<object>>(value,settings);

产生以下JSON:

{"$type":"System.Collections.Generic.List`1[[System.Object, mscorlib]], mscorlib","$values":["9d7aa4d3-a340-4cee-baa8-6af0582b8acd","2014-07-28T21:03:17.1287029-04:00"]}

如您所见,列表项已丢失其类型信息。反序列化相同的JSON将导致列表只包含字符串。

此问题之前曾在codeplex上报告并且已经完全关闭,说明包含类型信息会使JSON过于混乱。我很惊讶我们没有给出单独的选项来包括原始类型信息,因为往返一致性被破坏了。

https://json.codeplex.com/workitem/23833

我希望数据返回时带有与之相同的类型信息。 有没有人有任何建议或解决方法可以解决这种不良行为?

谢谢,

克里斯

2 个答案:

答案 0 :(得分:15)

以下是使用自定义JsonConverter的解决方案:

public sealed class PrimitiveJsonConverter : JsonConverter
{
    public PrimitiveJsonConverter()
    {

    }

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

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        switch (serializer.TypeNameHandling)
        {
            case TypeNameHandling.All:
                writer.WriteStartObject();
                writer.WritePropertyName("$type", false);

                switch (serializer.TypeNameAssemblyFormat)
                {
                    case FormatterAssemblyStyle.Full:
                        writer.WriteValue(value.GetType().AssemblyQualifiedName);
                        break;
                    default:
                        writer.WriteValue(value.GetType().FullName);
                        break;
                }

                writer.WritePropertyName("$value", false);
                writer.WriteValue(value);
                writer.WriteEndObject();
                break;
            default:
                writer.WriteValue(value);
                break;
        }
    }
}

以下是如何使用它:

JsonSerializerSettings settings = new JsonSerializerSettings() 
{ 
    TypeNameHandling = TypeNameHandling.All,
};

settings.Converters.Insert(0, new PrimitiveJsonConverter());
return JsonConvert.SerializeObject(myDotNetObject, settings);

我目前正在使用此解决方案序列化可包含基元的IDictionary<string, object>实例。

答案 1 :(得分:2)

将它们混合在一起并进行测试。显然,这需要单元测试,更像是一个概念验证。如果你想要一个肮脏的解决方案让你去,这应该开始。

https://github.com/xstos/Newtonsoft.Json/commit/8d3507cbba78f7096a82e42973e56d69c9541c42