c# - 带有 TypeNameHandling=auto 的 IEnumerable 的 Json.Net 序列化

标签 c# json.net

根据 Json.Net documentation所有 IEnumerable 类型都应序列化为 json 数组。

所以我期待以下类(class):

public class MyClass
{
    public IEnumerable<string> Values { get; set; }
}

被序列化为:

{
    "Values": []
}

问题是,当我使用 TypeNameHandling=Auto 时,我得到:

{
    "Values": {
        "$type": "System.String[], mscorlib",
        "$values": []
    }
}

我需要 TypeNameHandling=Auto 用于其他属性,但我希望 IEnumerable 使用默认序列化。其他类型(例如 IList)按预期工作。

这是一个错误还是我遗漏了什么?

这里是重现问题的完整代码:

    [Test]
    public void Newtonsoft_serialize_list_and_enumerable()
    {
        var target = new Newtonsoft.Json.JsonSerializer
        {
            TypeNameHandling = TypeNameHandling.Auto
        };

        var myEvent = new MyClass
        {
            Values = new string[0]
        };

        var builder = new StringWriter();
        target.Serialize(builder, myEvent);
        var json = JObject.Parse(builder.ToString());

        Assert.AreEqual(JTokenType.Array, json["Values"].Type);
    }

    public class MyClass
    {
        public IEnumerable<string> Values { get; set; }
    }

我正在使用 Newtonsoft 7.0.1。

更新: 这是另一个使用更多类型的测试:

    [Test]
    public void Newtonsoft_serialize_list_and_enumerable()
    {
        var target = new Newtonsoft.Json.JsonSerializer
        {
            TypeNameHandling = TypeNameHandling.Auto
        };

        var myEvent = new MyClass
        {
            Values1 = new string[0],
            Values2 = new List<string>(),
            Values3 = new string[0],
            Values4 = new List<string>(),
            Values5 = new string[0]
        };

        var builder = new StringWriter();
        target.Serialize(builder, myEvent);
        var json = builder.ToString();
    }

    public class MyClass
    {
        public IEnumerable<string> Values1 { get; set; }
        public IEnumerable<string> Values2 { get; set; }
        public IList<string> Values3 { get; set; }
        public IList<string> Values4 { get; set; }
        public string[] Values5 { get; set; }
    }

这是结果:

{
    "Values1": {
        "$type": "System.String[], mscorlib",
        "$values": []
    },
    "Values2": [],
    "Values3": {
        "$type": "System.String[], mscorlib",
        "$values": []
    },
    "Values4": [],
    "Values5": []
}

我还是不明白为什么我会根据组合得到不同的结果。

最佳答案

当反序列化为 IEnumerable 时,Json.Net 的默认自动行为或 IList字段,就是创建一个List实例。如果您分配 Array实例,那么将对象恢复到其原始实例状态的唯一方法是让 Json.Net 添加 $type元数据,这就是您所看到的。 即有很多方法可以反序列化为 IEnumerable字段。

通过使用 List<string>实例:

var myEvent = new MyClass
{
    Values = new List<string>(),
};

与:

public class MyClass
{
   public IEnumerable<string> Values { get; set; }
}    

结果(序列化时):

{"Values":["hello"]}

此外,如果您使用显式可构造类型或使用默认列表,则 Json.Net 将使用它并省略 $type ;

例如:

string[] Values { get; set; } = new string[0]; // not needed
IEnumerable<string> Values { get; set; } = new string[0]; //$type needed
IEnumerable<string> Values { get; set; } = new Stack<string>(); //$type needed
IEnumerable<string> Values { get; set; } = new List<string>; // not needed
List<string> Values { get; set; } = new List<string>; // not needed

ObservableCollection<string> Values { get; set; } = 
    new ObservableCollection<string>(); // not needed

关于c# - 带有 TypeNameHandling=auto 的 IEnumerable 的 Json.Net 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34662966/

相关文章:

c# - 用于数据库访问的静态类的 ASP.NET MVC 指南

c# - 如何自定义验证属性错误信息?

c# - ASP.NET 成员(member)电子邮件验证

c# - 调用 DeserializeObject<Object>( ... ) 时验证 Json 数据

c# - 获取 JSON 文件中的元素名称

c# - Asp.Net Mvc4 : How to use @ character in js file

c# - 在客户端和服务器之间保护用户名/密码的最佳实践

c# - 如何命名 c# 类字段以便能够反序列化具有无效字符的 json 字段名称

c# - 根据属性的运行时值选择性地序列化属性

c# - JSON.net,C#,无法在数据模型中设置默认值