使用值元组键反序列化字典时出现错误。我认为它将元组转换为字符串,然后无法将其反序列化为键:
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);
答案 0 :(得分:1)
就像您已经在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 elements = Convert.ToString(value).Trim('(').Trim(')').Split(new[] {','},StringSplitOptions.RemoveEmptyEntries);
return (elements.First(),elements.Last());
}
}
现在,您可以执行以下操作。
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);
答案 1 :(得分:0)
我可以从您的问题中得知,您以某种方式在json对象中有一个(1, 2)
,这不是newtonsoft如何序列化元组的,因此,如果没有自定义反序列化程序,它将无法将其序列化。 Newtonsoft将Tuples序列化为{"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);