给定两个类如下:
class ListCollection : List<int>
{
}
[Serializable]
class PrivateListCollection: ISerializable
{
private List<int> list = new List<int>();
public void Add(int value)
{
list.Add(value);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("items", list);
}
}
我在将1,2,3添加到它们中的每一个并使用JsonConvert.SerializeObject序列化后得到了这个:
ListCollection: [1,2,3]
PrivateListCollection: {"items":[1,2,3]}
问题是,是否可以将PrivateListCollection的序列化结果作为[1,2,3](没有前面的"项"或其他内容(?
POCO无法通过实现ISerializable
将自己序列化为JSON数组,因为JSON数组是一个有序的值序列,而SerializationInfo
表示一个名称/值对的集合,它与JSON对象而不是数组的定义完全匹配。Json.NET文档确认了这一点:
I可串行化
实现ISerializable并用SerializableAttribute标记的类型被序列化为JSON对象。序列化时,仅使用从ISerializable.GetObjectData返回的值;类型上的成员将被忽略。反序列化时,会调用具有SerializationInfo和StreamingContext的构造函数,传递JSON对象的值。
要将PrivateListCollection
序列化为JSON数组,您有几个选项。
首先,您可以创建一个自定义JsonConverer
:
class PrivateListCollectionConverter : JsonConverter<PrivateListCollection>
{
const string itemsName = "items";
public override PrivateListCollection ReadJson(JsonReader reader, Type objectType, PrivateListCollection existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var list = serializer.Deserialize<List<int>>(reader);
if (list == null)
return null;
existingValue = existingValue ?? new PrivateListCollection();
foreach (var item in list)
existingValue.Add(item);
return existingValue;
}
public override void WriteJson(JsonWriter writer, PrivateListCollection value, JsonSerializer serializer)
{
// There doesn't seem to be any way to extract the items from the PrivateListCollection other than to call GetObjectData(), so let's do that.
// Adding PrivateListCollectionConverter as a nested type inside PrivateListCollection would be another option to make the items accessible.
ISerializable serializable = value;
var info = new SerializationInfo(value.GetType(), new FormatterConverter());
serializable.GetObjectData(info, serializer.Context);
var list = info.GetValue(itemsName, typeof(IEnumerable<int>));
serializer.Serialize(writer, list);
}
}
然后将其添加到PrivateListCollection
中,如下所示:
[Serializable]
[JsonConverter(typeof(PrivateListCollectionConverter))]
class PrivateListCollection: ISerializable
{
// Remainder unchanged
或者像这样将其添加到JsonSerializerSettings
中:
var settings = new JsonSerializerSettings
{
Converters = { new PrivateListCollectionConverter() },
};
在这里演示小提琴#1。
其次,您可以使PrivateListCollection
实现IEnumerable<int>
,并添加一个参数化构造函数,该构造函数采用单个IEnumerable<int>
参数,如下所示:
[Serializable]
class PrivateListCollection: ISerializable, IEnumerable<int>
{
public PrivateListCollection() { }
public PrivateListCollection(IEnumerable<int> items) => list.AddRange(items);
private List<int> list = new List<int>();
public void Add(int value)
{
list.Add(value);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("items", list);
}
public IEnumerator<int> GetEnumerator() => list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
这样,Json.NET将把PrivateListCollection
看作是一个可构造的只读集合,它可以作为Json数组进行往返。但是,基于您已将类型命名为PrivateListCollection
的事实,您可能不希望实现枚举。
在这里演示小提琴#2。