简体   繁体   English

Json对Tuples反序列化有问题吗?

[英]Json deserialization issues with Tuples?

I have a class I use for configuration that holds a 3 tuple of all integers. 我有一个用于配置的类,其中包含所有整数的3个元组。

public class Configuration
{
    public List<Tuple<int, int, int>> MyThreeTuple { get; set; }

    public Configuration()
    {
        MyThreeTuple = new List<Tuple<int, int, int>>();
        MyThreeTuple.Add(new Tuple<int, int, int>(-100, 20, 501));
        MyThreeTuple.Add(new Tuple<int, int, int>(100, 20, 864));
        MyThreeTuple.Add(new Tuple<int, int, int>(500, 20, 1286));
    }
}

This class is serialized into Json with System.Web.Script.Serialization as such 此类通过System.Web.Script.Serialization序列化到Json中

JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
String configJson = jsonSerializer.Serialize(config);
File.WriteAllText(configPath, configJson);

and then deserialized when the application is launched 然后在启动应用程序时反序列化

String configJson = File.ReadAllText(configPath);
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer(); 
object jsonObject = jsonSerializer.Deserialize(configJson, typeof(ApplicationConfiguration));
appConfig = (Configuration)jsonObject;

My issue is that whenever I go to deserialize the Json an exception is thrown 我的问题是,每当我对Json进行反序列化时,都会引发异常

System.MissingMethodException in System.Web.Extensions.dll 

With the message 随着消息

No parameterless constructor defined for type of `System.Tuple`3 ....

This is what the produced Json for the tuple looks like 这就是为元组生成的Json的样子

"MyThreeTuple":
 [
    {"Item1":-100,"Item2":20,"Item3":501},
    {"Item1":100,"Item2":20,"Item3":864},
    {"Item1":500,"Item2":20,"Item3":1286}
 ]

Any idea how to solve this problem? 任何想法如何解决这个问题?

EDIT: 编辑:

As other have suggested I tried out JSon.NET and it seems to work to deserialize the json. 正如其他建议一样,我尝试了JSon.NET,并且似乎可以反序列化json。 Though I have found an odd quirk. 尽管我发现了一个奇怪的怪癖。

So the constructor for my Configuration class fills in default values for the configuration. 因此,我的Configuration类的构造函数将填写Configuration默认值。 Specifically what is given in the code above. 具体来说,上面的代码中给出了什么。 I have found that I can serialize the configuration with different values, but when deserialized, the default values are also loaded to the List<Tuple<>> . 我发现我可以使用不同的值序列化配置,但是反序列化时,默认值也会加载到List<Tuple<>>

I assume the Json.Net gets around the issue of Tuple not having a parameterless constructor by first instantiating Configuration and then setting its values. 我假设Json.Net通过首先实例化Configuration然后设置其值来解决Tuple没有无参数构造函数的问题。

It seems to be instantiating the class, then List.Add ing the Tuple s it finds in the json to the list. 似乎先实例化该类,然后实例化List.Add 。将在json中找到的Tuple到列表中。 Instead of clearing the list then adding what it finds. 而不是清除列表,而是添加找到的内容。

Is there an option in JSon.Net to solve this issue? JSon.Net中是否有解决此问题的选项?

The reason why you got this error because JavascriptSerializer requires a public parameter-less constructor which is not the case for Tuple because it's an immutable 之所以出现此错误,是因为JavascriptSerializer需要一个无参数的公共构造函数,对于Tuple而言,情况并非如此,因为它是immutable

take a look here http://json.codeplex.com/ for full comparison between javascriptserializer and json.net 在这里查看http://json.codeplex.com/,以全面了解javascriptserializer和json.net

Even microsoft states in the documentation 甚至Microsoft在文档中都声明

Json.NET should be used serialization and deserialization. 应该使用Json.NET进行序列化和反序列化。 Provides serialization and deserialization functionality for AJAX-enabled applications. 为启用AJAX的应用程序提供序列化和反序列化功能。

here an example on how you can easily use JsonConvert to achieve this 这是一个有关如何轻松使用JsonConvert实现此目的的示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;

namespace ConsoleApplication25
{
    class Program
    {
        static void Main(string[] args)
        {
            Configuration configuration = new Configuration();
            string configJson = JsonConvert.SerializeObject(configuration);
            File.WriteAllText(configPath, configJson);
            //Deserialize the  content after you read your file in string 

             var   configurationDeserialized = JsonConvert.DeserializeObject<Configuration>(configJson); 



        }
    }
}

public class Configuration
{
     [JsonIgnore]
    public List<Tuple<int, int, int>> MyThreeTuple { get; set; }

    public Configuration()
    {
        MyThreeTuple = new List<Tuple<int, int, int>>();
        MyThreeTuple.Add(new Tuple<int, int, int>(-100, 20, 501));
        MyThreeTuple.Add(new Tuple<int, int, int>(100, 20, 864));
        MyThreeTuple.Add(new Tuple<int, int, int>(500, 20, 1286));
    }
}

You can resolve using Newtonsoft.Json 您可以使用Newtonsoft.Json解决

  1. Install Newtonsoft.Json using nuget ( https://www.nuget.org/packages/Newtonsoft.Json/ ) 使用nuget安装Newtonsoft.Json( https://www.nuget.org/packages/Newtonsoft.Json/

Serialize : 序列化:

var myObject = new Configuration();
var objString = JsonConvert.SerializeObject(myObject);

Deserialize: 反序列化:

 var result = JsonConvert.DeserializeObject(objString, typeof(Configuration)); 

Or 要么

var result = JsonConvert.DeserializeObject<Configuration>(objString);

Just for completeness, I wanted to point out that it is possible to deserialize a Tuple<int, int, int> using the JavaScriptSerializer , but you need a JavaScriptConverter to do it. 只是为了完整性,我想指出,这可能的反序列化Tuple<int, int, int>使用JavaScriptSerializer ,但你需要一个JavaScriptConverter做到这一点。 The converter handles instantiating the Tuple from the values in the JSON, thus avoiding the exception. 转换器处理从JSON中的值实例化Tuple ,从而避免异常。

class ThreeTupleConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type> { typeof(Tuple<int, int, int>) }; }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        int item1 = (int)dictionary["Item1"];
        int item2 = (int)dictionary["Item2"];
        int item3 = (int)dictionary["Item3"];
        return new Tuple<int, int, int>(item1, item2, item3);
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

To use the converter, you must register it with the serializer like this: 要使用转换器,您必须像下面这样在串行器中注册它:

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new List<JavaScriptConverter> { new ThreeTupleConverter() });

Then deserialize as you normally would, and it should work fine: 然后像往常一样反序列化,它应该可以正常工作:

string configJson = @"
{
    ""MyThreeTuple"":
    [
        { ""Item1"": -100, ""Item2"": 20, ""Item3"": 501 },
        { ""Item1"": 100, ""Item2"": 20, ""Item3"": 864 },
        { ""Item1"": 500, ""Item2"": 20, ""Item3"": 1286 }
    ]
}";

var config = serializer.Deserialize<Configuration>(configJson);

foreach (var tuple in config.MyThreeTuple)
{
    Console.WriteLine("(" + tuple.Item1 + ", " + tuple.Item2 + ", " + tuple.Item3 + ")");
}

Output: 输出:

(-100, 20, 501)
(100, 20, 864)
(500, 20, 1286)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM