[英]newtonsoft json.net - deserializing dictionary with value tuple key
反序列化具有值元组键的字典时出现错误。 我认为它将元组转换为字符串然后无法将其反序列化为键:
Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Could not convert string '(1, 2)' to dictionary key type 'System.ValueTuple`2[System.Int32,System.Int32]'. Create a TypeConverter to convert from the string to the key type object. Path 'Types['(1, 2)']', line 1, position 49.
Source=Newtonsoft.Json
StackTrace:
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at ConsoleApp.Program.Main(String[] args) in D:\Open Source\JsonSerilization\ConsoleApp\ConsoleApp\Program.cs:line 65
Inner Exception 1:
JsonSerializationException: Error converting value "(1, 2)" to type 'System.ValueTuple`2[System.Int32,System.Int32]'. Path 'Types['(1, 2)']', line 1, position 49.
Inner Exception 2:
ArgumentException: Could not cast or convert from System.String to System.ValueTuple`2[System.Int32,System.Int32].
有没有标准的解决方案?
到目前为止,我似乎需要提供一个自定义转换器; 这看起来很乏味。
更新:
这是我尝试序列化/反序列化的类:
public sealed class Message
{
[JsonConstructor]
internal Message()
{ }
public ISet<(int Id, int AnotherId)> Ids { get; set; }
= new HashSet<(int Id, int AnotherId)>();
public Dictionary<(int Id, int AnotherId), int> Types { get; set; }
= new Dictionary<(int Id, int AnotherId), int>();
}
这是我使用它的地方:
var message = new Message();
message.Ids.Add((1, 2));
message.Types[(1, 2)] = 3;
var messageStr = JsonConvert.SerializeObject(message);
var messageObj = JsonConvert.DeserializeObject<Message>(messageStr);
就像您在 OP 中已经提到的那样,TypeConverter 在这里对反序列化元组键很有用。 但它可能并不像看起来那么乏味。
例如,您可以编写一个简单的 TypeConverter,如下所示。
public class TupleConverter<T1, T2>: TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context,CultureInfo culture, object value)
{
var key = Convert.ToString(value).Trim('(').Trim(')');
var parts = Regex.Split(key, (", "));
var item1 = (T1)TypeDescriptor.GetConverter(typeof(T1)).ConvertFromInvariantString(parts[0])!;
var item2 = (T2)TypeDescriptor.GetConverter(typeof(T2)).ConvertFromInvariantString(parts[1])!;
return new ValueTuple<T1, T2>(item1, item2);
}
}
现在,您可以执行以下操作。
var dictionary = new Dictionary<(string,string),int>
{
[("firstName1","lastName1")] = 5,
[("firstName2","lastName2")] = 5
};
TypeDescriptor.AddAttributes(typeof((string, string)), new TypeConverterAttribute(typeof(TupleConverter<string, string>)));
var json = JsonConvert.SerializeObject(dictionary);
var result = JsonConvert.DeserializeObject<Dictionary<(string,string),string>>(json);
我可以从您的问题中得知,您的 json 对象中以某种方式获得了(1, 2)
,这不是 newtonsoft 序列化元组的方式,因此如果没有自定义反序列化器,将无法将其序列化。 Newtonsoft 将元组序列化为{"Item1" : 1, "Item2": 2}
。 这就是您的代码不起作用的原因。 如果您无法更改输入,则必须编写自定义解串器,但我建议将输入更改为标准。 这里的代码是你如何序列化/反序列化一个元组:
var dictionary = new Dictionary<string, Tuple<int, int>>();
dictionary.Add("test", new Tuple<int, int>(1, 2));
var serializeObject = JsonConvert.SerializeObject(dictionary);
var deserializeObject = JsonConvert.DeserializeObject<Dictionary<string, Tuple<int, int>>>(serializeObject);
Assert.AreEqual(deserializeObject["test"].Item1, 1);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.