C# - Json.NET - 具有继承的序列化
本文关键字:继承 序列化 Json NET | 更新日期: 2023-09-27 17:56:23
我有这个类:
using Sierra.Collections;
namespace Sierra
{
public sealed class Worlds : SafeKeyedCollection<byte, World>
{
public Worlds() : base() { }
protected override byte GetKeyForItem(World item)
{
return item.Id;
}
}
}
世界级:
using Sierra.Collections;
namespace Sierra
{
public sealed class World : SafeKeyedCollection<byte, Channel>
{
public byte Id { get; set; }
public string Name { get; set; }
public ushort Port { get; set; }
public ushort ShopPort { get; set; }
public ushort MonsterLifePort { get; set; }
public ushort TalkPort { get; set; }
public byte Ribbon { get; set; }
public byte Channels { get; set; }
public string EventMessage { get; set; }
public string ScrollingHeader { get; set; }
public bool AllowMultiLeveling { get; set; }
public int DefaultCreationSlots { get; set; }
public bool DisableCharacterCreation { get; set; }
public World() : base() { }
protected override byte GetKeyForItem(Channel item)
{
return item.Id;
}
}
}
当我Worlds
对象时,它不会序列化它。列表显示为空:
public Worlds Worlds { get; set; }
它输出:
"Worlds": [
[]
]
这是为什么呢?不能序列化从另一个类继承的类吗?
安全钥匙收藏
using System;
using System.Collections;
using System.Collections.Generic;
namespace Sierra.Collections
{
/// <summary>
/// Thread safe NumericalKeyedCollection class - Patel
/// Soooooooooooooo fire
/// </summary>
public abstract class SafeKeyedCollection<TKey, TItem> : IEnumerable<TItem>
{
private Object m_Lock;
private Dictionary<TKey, TItem> m_Inner;
public SafeKeyedCollection()
{
m_Lock = new object();
m_Inner = new Dictionary<TKey, TItem>();
}
public int Count
{
get
{
lock (m_Lock)
{
return m_Inner.Count;
}
}
}
public TItem this[TKey key]
{
get
{
lock (m_Lock)
{
TItem ret;
m_Inner.TryGetValue(key, out ret);
return ret;
}
}
}
public void Add(TItem item)
{
this.InsertItem(item);
}
public void Remove(TItem item)
{
this.RemoveItem(item);
}
protected virtual void InsertItem(TItem item)
{
lock (m_Lock)
{
TKey key = GetKeyForItem(item);
m_Inner.Add(key, item);
}
}
protected virtual void RemoveItem(TItem item)
{
lock (m_Lock)
{
TKey key = GetKeyForItem(item);
m_Inner.Remove(key);
}
}
public void Clear()
{
lock (m_Lock)
{
m_Inner.Clear();
}
}
public bool Contains(TKey key)
{
lock (m_Lock)
{
return m_Inner.ContainsKey(key);
}
}
public bool Contains(TItem value)
{
lock (m_Lock)
{
return m_Inner.ContainsValue(value);
}
}
protected abstract TKey GetKeyForItem(TItem item);
protected virtual void ClearItems() { }
public IEnumerator<TItem> GetEnumerator()
{
return new SafeEnumerator<TItem>(() => m_Inner.Values.GetEnumerator(), m_Lock);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
谢谢
基本问题是您正在尝试序列化已子类化以包含自定义属性的集合(此处SafeKeyedCollection<TKey, TItem> : IEnumerable<TItem>
)。 这是无法完成的,因为 JSON 标准只定义了两种类型的容器:
- 具有命名键/值属性的对象:
{"a": 1, "b" : "two" }
- 元素数组:
[1, 2, 3, {"a": 1}]
没有容器可以同时具有命名属性和任意数量的未命名元素 - 在序列化中,项或属性必须优先。 事实上,默认情况下,所有 JSON 序列化程序都选择将实现IEnumerable
的任何内容序列化为数组,省略属性。 这就是你所看到的。 通常,您可以序列化从另一个类继承的类,只是不能序列化子类化集合的可设置属性。
如何处理这个问题? Microsoft馆藏指南声明
避免在具有与集合概念无关的复杂 API 的类型上实现集合接口。
因此,您可以考虑更改数据模型(这也会导致XmlSerializer
问题),以使集合包含在某个更高的对象中,而不是子类化。
如果您希望保留当前数据模型,则可用的解决方法取决于您使用的序列化程序:
- 使用 Json.NET,您可以使用
JsonObjectAttribute
标记您的类,然后创建一些私有的 get/set 代理属性来序列化元素。 - 同样使用 Json.NET,您可以为您的集合创建自定义转换器。 请参阅自定义集合(具有集合属性)的 JSON.NET。
- 如果使用
DataContractJsonSerializer
则可以使用数据协定代理项将集合映射到包含嵌套集合中的集合项的类。