代码之家  ›  专栏  ›  技术社区  ›  Davide Icardi i3arnon

杰森。TypeNameHandling=auto的IEnumerable的净序列化

  •  9
  • Davide Icardi i3arnon  · 技术社区  · 10 年前

    根据 Json.Net documentation 全部的 IEnumerable 类型应序列化为json数组。

    因此,我期望以下课程:

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

    要序列化为:

    {
        "Values": []
    }
    

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

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

    我需要 TypeNameHandling=自动 但我希望 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": []
    }
    

    再一次,我不明白为什么我会根据组合得到不同的结果。

    2 回复  |  直到 10 年前
        1
  •  6
  •   urig    10 年前

    Json的默认自动行为。Net,当反序列化为 IEnumerable IList 字段,用于创建 List 例子如果您分配 Array 实例,那么将对象恢复到其原始实例状态的唯一方法是使用Json。Net添加 $type 元数据,这就是你所看到的。 i、 e.有许多方法可以反序列化为 IEnumerable(可计算) 领域

    通过使用 List<string> 实例:

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

    具有:

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

    结果(序列化时):

    {"Values":["hello"]}
    

    此外,如果使用显式可构造类型或使用默认的List,那么Json。Net将使用它并省略 $类型 ;

    例如:

    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
    
        2
  •  2
  •   vendettamit    10 年前

    这不是bug,但这是预期的行为。您正在设置 TypeNameHandling 全球地。不必全局设置类型名称处理,您可以用下面这样的属性标记属性,以避免将它们包含在设置中 TypeNameHandling.Auto :

    [JsonProperty(TypeNameHandling = TypeNameHandling.None)]
    

    下面是一个示例:

        public class MyClass
        {
            // Indicate the property not to apply any type handling
            [JsonProperty(TypeNameHandling=TypeNameHandling.None)]
            public IList<string> Values { get; set; }
    
            public string Name { get; set; }
        }
    

    这将在不受任何影响的情况下提供您想要的结果 类型名称处理 全局声明的设置。