Json.net实现IEnumerable <T>的自定义集合的序列化

pmc*_*ath 15 c# serialization json json.net

我有一个实现IEnumerable的集合类,我无法反序列化相同的序列化版本.我正在使用Json.net v 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
  }
}
Run Code Online (Sandbox Code Playgroud)

当我序列化它时,我得到以下json

[
  {
    "Number": 1
  },
  {
    "Number": 2
  }
]
Run Code Online (Sandbox Code Playgroud)

但是当我尝试反序列化时,我得到以下异常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);
}
Run Code Online (Sandbox Code Playgroud)

有人设法序列化自己的集合对象吗?

提前致谢

dbc*_*dbc 8

从Json.NET 6.0 Release 3及更高版本开始(我在8.0.3上测试过),只要实现的自定义类IEnumerable<MyType>具有带IEnumerable<MyType>输入参数的构造函数,它就会自动运行.从发行说明:

对于所有未来的不可变.NET集合的创建者:如果你的T集合有一个带有IEnumerable的构造函数,那么当反序列化到你的集合时,Json.NET会自动工作,否则你都会运气不好.

由于问题中的MyTypes类只有这样的构造函数,所以现在只能工作.示范小提琴:https://dotnetfiddle.net/LRJHbd.

如果没有这样的构造函数,则需要添加无参数构造函数并使用工作方法实现ICollection<MyType>(而不是仅仅IEnumerable<MyType>)Add(MyType item).然后Json.NET可以构建和填充集合.或者像原始答案一样反序列化为中间集合.


Chr*_*ola 2

我相信 JSON .NET 依赖于它反序列化到的类型的无参数构造函数。从反序列化的角度来看,它不知道要向构造函数提供什么。

至于您的集合,它又应该如何知道如何填充一个实现,该实现IEnumerable<T>仅定义如何枚举集合而不是如何填充它。您应该直接反序列化到某个标准IEnumerable<MyType>(或者直接反序列化到IEnumerable<MyType>我认为 JSON.NET 支持的标准),然后将其传递给您的构造函数。

我相信以下所有内容都应该在这种情况下起作用:

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));
Run Code Online (Sandbox Code Playgroud)

或者,虽然需要做更多工作,但如果您需要直接反序列化,您可以在集合上实现类似 IList 的东西,这应该允许 JSON.NET 使用 IList 方法来填充您的集合。