如何正确地将元组序列化为键字典
Posted
技术标签:
【中文标题】如何正确地将元组序列化为键字典【英文标题】:How to properly serialize tuple as key dictionary 【发布时间】:2012-09-04 16:04:39 【问题描述】:我有以下应用程序显示字典的关键部分没有发送到JsonConverter
,但它被称为ToString()
on。这对我来说是个问题,因为我无法反序列化我的 Json
string 。
有什么想法吗?
class Program
static void Main(string[] args)
var coll = new Dictionary<Tuple<string,string>, string>();
coll.Add(Tuple.Create("key1", "KEY1"), "Value1");
coll.Add(Tuple.Create("key2", "KEY2"), "Value2");
string json = JsonConvert.SerializeObject(coll);
Dictionary<Tuple<string, string>, string> coll2;
Console.WriteLine(json);
//coll2 = JsonConvert.DeserializeObject<Dictionary<Tuple<string, string>, string>>(json);
// It throws an exception here
//foreach (var k in coll2)
//
// Console.WriteLine("<0|1>",k.Key, k.Value);
//
var t = Tuple.Create("key1", "key2");
Console.WriteLine(t.ToString());
string json2 = JsonConvert.SerializeObject(t);
Console.WriteLine(json2);
输出:
"(key1, KEY1)":"Value1","(key2, KEY2)":"Value2" (key1, key2) "Item1":"key1","Item2":"key2" 按任意键继续 。 . .
【问题讨论】:
在这种情况下“正确序列化”是什么意思?你能告诉我们你想得到什么输出吗? 如果调用了 JsonConverter,@siride: "Item1":"key1","Item2":"key2" 将是输出。 为什么你使用字典而不是元组"AStringAsKey":AnObject
,而一个字典被序列化为"key1":value1,"key2":value2
所以你的元组的序列化版本不能用作key。因此 Json Serializer 调用 ToString 将字典的键(你的元组)转换为字符串
这只是一个显示序列化问题的例子,我的字典中会有更多的键/值对。
【参考方案1】:
在反序列化以元组为键的字典时,我也遇到了同样的问题。 JSON 将元组转换为纯字符串。但就我而言,我无法避免使用元组作为字典中的键。所以我做了一个自定义的 JSON 转换器来反序列化以元组为键的字典,它运行良好。
我已根据您的代码进行了相同的修改。希望它能正常工作,并可以让您了解 JSON CustomConverter。也可以用 cmets 更好地解释。
public class TupleKeyConverter : JsonConverter
/// <summary>
/// Override ReadJson to read the dictionary key and value
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
Tuple<string, string> _tuple = null;
string _value = null;
var _dict = new Dictionary<Tuple<string, string>, string>();
//loop through the JSON string reader
while (reader.Read())
// check whether it is a property
if (reader.TokenType == JsonToken.PropertyName)
string readerValue = reader.Value.ToString();
if (reader.Read())
// check if the property is tuple (Dictionary key)
if (readerValue.Contains('(') && readerValue.Contains(')'))
string[] result = ConvertTuple(readerValue);
if (result == null)
continue;
// Custom Deserialize the Dictionary key (Tuple)
_tuple = Tuple.Create<string, string>(result[0].Trim(), result[1].Trim());
// Custom Deserialize the Dictionary value
_value = (string)serializer.Deserialize(reader, _value.GetType());
_dict.Add(_tuple, _value);
else
// Deserialize the remaining data from the reader
serializer.Deserialize(reader);
break;
return _dict;
/// <summary>
/// To convert Tuple
/// </summary>
/// <param name="_string"></param>
/// <returns></returns>
public string[] ConvertTuple(string _string)
string tempStr = null;
// remove the first character which is a brace '('
if (_string.Contains('('))
tempStr = _string.Remove(0, 1);
// remove the last character which is a brace ')'
if (_string.Contains(')'))
tempStr = tempStr.Remove(tempStr.Length - 1, 1);
// seperate the Item1 and Item2
if (_string.Contains(','))
return tempStr.Split(',');
return null;
/// <summary>
/// WriteJson needs to be implemented since it is an abstract function.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
serializer.Serialize(writer, value);
/// <summary>
/// Check whether to convert or not
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
public override bool CanConvert(Type objectType)
return true;
现在如下声明一个属性。 JsonConvertor 属性很重要。
[JsonConverter(typeof(TupleKeyConverter))]
public Dictionary<Tuple<int,string>,string> MyDict get; set;
或者您可以尝试在您的代码中替换它。虽然我从未测试过。
coll2 = JsonConvert.DeserializeObject<Dictionary<Tuple<string, string>, string>>("", new TupleKeyConverter());
【讨论】:
这很好用!但是,假设字典值不是字符串,而是具有多个值的实际对象。您将如何修改上述代码以允许通常的 JSON 反序列化器处理对象的反序列化。 这对我的元组键属性非常有用,但由于某种原因,它尝试对其他类成员使用相同的 JsonConverter - 是否将自己设置为默认转换器或其他东西? 我必须添加 if (reader.TokenType == JsonToken.EndObject) break; 以使其正常工作。【参考方案2】:根据您提供的信息,我建议不要使用元组作为键,而是使用自定义结构或对象并覆盖 ToString 方法。然后你可以随意序列化/反序列化。
【讨论】:
以上是关于如何正确地将元组序列化为键字典的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将 asp.net 核心模型状态错误反序列化为 xamarin 形式的对象