【问题标题】:Json deserialization issues with Tuples?元组的 Json 反序列化问题?
【发布时间】:2015-10-30 13:15:45
【问题描述】:

我有一个用于配置的类,它包含所有整数的 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));
    }
}

这个类被序列化为带有System.Web.Script.Serialization的Json

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

然后在应用启动时反序列化

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

我的问题是每当我去反序列化 Json 时都会引发异常

System.MissingMethodException in System.Web.Extensions.dll 

有消息

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

这是为元组生成的 Json 的样子

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

知道如何解决这个问题吗?

编辑:

正如其他人建议的那样,我尝试了 JSon.NET,它似乎可以反序列化 json。虽然我发现了一个奇怪的怪癖。

所以我的Configuration 类的构造函数填充了配置的默认值。特别是上面代码中给出的内容。我发现我可以用不同的值对配置进行序列化,但是在反序列化时,默认值也会加载到List&lt;Tuple&lt;&gt;&gt;

我假设 Json.Net 通过首先实例化 Configuration 然后设置其值来解决 Tuple 没有无参数构造函数的问题。

它似乎正在实例化该类,然后 List.Adding 将它在 json 中找到的 Tuples 添加到列表中。而不是清除列表然后添加它找到的内容。

JSon.Net 中有解决此问题的选项吗?

【问题讨论】:

标签: c# json serialization json.net javascriptserializer


【解决方案1】:

出现此错误的原因是 JavascriptSerializer 需要一个公共无参数构造函数,而 Tuple 则不是这种情况,因为它是一个 immutable

在这里查看http://json.codeplex.com/ 以了解 javascriptserializer 和 json.net 之间的完整比较

甚至documentation中的微软状态

Json.NET 应该使用序列化和反序列化。为支持 AJAX 的应用程序提供序列化和反序列化功能。

这里有一个示例,说明如何轻松使用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));
    }
}

【讨论】:

  • 你的例子的测试没有意义。由于new Configuration() 已经添加了三个元组,因此您的测试无法区分MyThreeTuple 根本没有被序列化,MyThreeTuple 被序列化但在反序列化期间被忽略,MyThreeTuple 被正确序列化和反序列化。 (但即使您的测试不正确,结果也可能是正确的。)
  • @hvd 你说得对,但用一个简单的 [JsonIgnore] 解决了
【解决方案2】:

为了完整起见,我想指出 可以使用 JavaScriptSerializer 反序列化 Tuple&lt;int, int, int&gt;,但您需要 JavaScriptConverter 来执行此操作。转换器处理从 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();
    }
}

要使用转换器,您必须像这样在序列化程序中注册它:

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

然后像往常一样反序列化,它应该可以正常工作:

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 + ")");
}

输出:

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

【讨论】:

    【解决方案3】:

    您可以使用 Newtonsoft.Json 解决

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

    序列化:

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

    反序列化:

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

    或者

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-23
      • 2021-05-28
      • 1970-01-01
      相关资源
      最近更新 更多