我有一个实现IEnumerable的集合类,并且在反序列化该集合类的序列化版本时遇到问题。我使用的是Json.net版本4.0.2.13623
下面是我的集合类的简化版本,它说明了我的问题
public class MyType
{
public int Number { get; private set; }
public MyType(int number)
{
this.Number = number;
}
}
public class MyTypes : IEnumerable<MyType>
{
private readonly Dictionary<int, MyType> c_index;
public MyTypes(IEnumerable<MyType> seed)
{
this.c_index = seed.ToDictionary(item => item.Number);
}
public IEnumerator<MyType> GetEnumerator()
{
return this.c_index.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public int CustomMethod()
{
return 1; // Just for illustration
}
}
当我序列化它时,我得到以下json
[
{
"Number": 1
},
{
"Number": 2
}
]
但是当我尝试反序列化时,我得到了以下异常System.Exception:无法创建和填充列表类型MyTypes
也尝试过使用序列化提示,但没有成功
这些是我使用的测试功能
public void RoundTrip()
{
var _myTypes1 = new MyTypes(new[] { new MyType(1), new MyType(2) });
var _jsonContent = JsonConvert.SerializeObject(_myTypes1, Formatting.Indented);
var _myTypes2 = JsonConvert.DeserializeObject<MyTypes>(_jsonContent);
}
public void RoundTripWithSettings()
{
var _myTypes1 = new MyTypes(new[] { new MyType(1), new MyType(2) });
var _serializationSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Arrays };
var _jsonContent = JsonConvert.SerializeObject(_myTypes1, Formatting.Indented, _serializationSettings);
var _myTypes2 = JsonConvert.DeserializeObject<MyTypes>(_jsonContent, _serializationSettings);
}
有人成功地序列化了自己的集合对象吗?
提前感谢
Pat
从Json.NET 6.0 Release 3及更高版本(我在8.0.3上进行了测试(开始,只要实现IEnumerable<MyType>
的自定义类具有接受IEnumerable<MyType>
输入参数的构造函数,它就会自动工作。来自发行说明:
对于所有未来不可变.NET集合的创建者:如果你的T集合有一个采用IEnumerable的构造函数,那么Json.NET将在反序列化到你的集合时自动工作,否则你就倒霉了。
由于问题中的MyTypes
类只有这样一个构造函数,所以现在只起作用。示范小提琴:https://dotnetfiddle.net/LRJHbd.
如果没有这样的构造函数,则需要添加一个无参数构造函数,并用一个有效的Add(MyType item)
方法实现ICollection<MyType>
(而不仅仅是IEnumerable<MyType>
(。Json.NET可以构造并填充集合。或者反序列化为中间集合,如原始答案中所示。
我认为JSON.NET依赖于为它反序列化的类型提供一个无参数构造函数。从反序列化的角度来看,它不知道该为constructor提供什么。
至于您的集合,它应该如何知道如何填充IEnumerable<T>
的实现,该实现只定义如何枚举集合,而不是如何填充集合。您应该直接反序列化为一些标准的IEnumerable<MyType>
(或直接反序列化到我认为JSON.NET支持的IEnumerable<MyType>
(,然后将其传递给您的构造函数。
我认为在这种情况下,以下所有内容都应该有效:
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<MyTypes[]>(_jsonContent));
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<List<MyTypes>>(_jsonContent));
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<IEnumerable<MyTypes>>(_jsonContent));
或者,尽管需要做更多的工作,但如果需要直接反序列化,可以在集合上实现类似IList的东西,这应该允许JSON.NET使用IList方法来填充集合。