c# - Tuple<...> 在另一种类型中的 Json.NET 反序列化不起作用?

标签 c# serialization json.net deserialization json-deserialization

使用 Json.net,反序列化包含 Tuple<...> 的类型不起作用(序列化有效,但反序列化无效):

[TestMethod]
public void Test()
{
    var orig = new TupleHolder("what????", true);
    var json = JsonConvert.SerializeObject(orig);
    Assert.AreEqual("{\"Tup\":{\"Item1\":\"what????\",\"Item2\":true}}", json);
    // great! serialization works like a charm! now let's test deserialization:
    var dupl = JsonConvert.DeserializeObject<TupleHolder>(json);

    Assert.AreEqual("ZZZ", dupl.Tup.Item1); // pass! but it should be "what????"... what????
    Assert.AreEqual(false, dupl.Tup.Item2); // pass! but it should be "true", right???

    Assert.AreEqual(orig.Tup.Item1, dupl.Tup.Item1); // fail!
    Assert.AreEqual(orig.Tup.Item2, dupl.Tup.Item2); // fail!
}

public class TupleHolder
{
    public Tuple<string, bool> Tup { get; set; }
    public TupleHolder() { Tup = new Tuple<string, bool>("ZZZ", false); }
    public TupleHolder(string s, bool b) { Tup = new Tuple<string, bool>(s, b); }
}

有趣的是 Tuple<...> 的直接反序列化确实有效:

[TestMethod]
public void Test2()
{
    var orig = new Tuple<string, bool>("ABC", true);
    var json = JsonConvert.SerializeObject(orig);
    var dupl = JsonConvert.DeserializeObject<Tuple<string, bool>>(json);
    Assert.AreEqual(orig, dupl); // direct deserialization of Tuple<...> works.
}

这是 Json.NET 错误还是我在这里遗漏了什么?

最佳答案

Remi 提供的答案帮助了我。我拿了他的TupleConverter并使其成为 2 元组的通用形式。这个概念对于任何 N 元组都是相同的。

我把它留在这里以防它对某人有帮助。

public class TupleConverter<U, V> : Newtonsoft.Json.JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Tuple<U, V>) == objectType;
    }

    public override object ReadJson(
        Newtonsoft.Json.JsonReader reader,
        Type objectType,
        object existingValue,
        Newtonsoft.Json.JsonSerializer serializer)
    {
        if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
            return null;

        var jObject = Newtonsoft.Json.Linq.JObject.Load(reader);

        var target = new Tuple<U, V>(
            jObject["m_Item1"].ToObject<U>(), jObject["m_Item2"].ToObject<V>());

        return target;
    }

    public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

Note: My Tuple was JSON serialized with m_Item1 and m_Item2, so I had to change jObject["ItemX"] to jObject["m_ItemX"]

使用示例 List<Tuple<int, User>> :

string result = "String to deserialize";
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new TupleConverter<int, User>());
List<Tuple<int, User>> users = JsonConvert.DeserializeObject<List<Tuple<int, User>>>(result, settings);

关于c# - Tuple<...> 在另一种类型中的 Json.NET 反序列化不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27898850/

相关文章:

c# - COM 对象 C# 将 MMDeviceEnumerator 转换为 IMMDeviceEnumerator InvalidCastException

c# - 播放背景音失败

java - 序列化 - 使用 ObjectStreamField [] serialPersistentFields 有什么好处?

c# - 反序列化不同类型的JSON数组

c# - 输入字符串不是有效数字 - JSON 反序列化

c# - 为什么这个 UWP Binding to decimal property 不能正常工作?

c# - 没有属性名称的Http get和post方法

java - 编码和序列化之间的澄清

python - Flask Marshmallow 使用额外字段序列化多对多关系

json.net - 在 Json.net 中全局设置 IgnoreSerializedAttribute