我试图序列化类Poll,看起来像这样:
class Poll
{
(...) //methods
public AnswersCollection answers { get; set; }
public TagsCollection tags { get; set; }
public string question { get; set; }
}
正如你所看到的,我有" TagsCollection"和" AnswersCollection",两者看起来都很相似,所以我只展示其中一个。
class AnswersCollection
{
(...) //methods
public List<Answer> answers { get; set; }
}
而且,最后,答案课。
class Answer
{
(...) //methods
public string name { get; set; }
public uint voteQuantity { get; set; }
}
所有clases都有默认的公共构造函数(没有参数),因此JSON.NET在序列化方面没有任何问题。
问题在于AnswersCollection(它是封装),因为它,JSON输出看起来像这样:
{
"answers":{
"answers":[
{
"name":"Foo",
"voteQuantity":45
},
{
"name":"Bar",
"voteQuantity":30
}
]
},
"tags":{
"tags":[
{
"name":"FooTag",
"id":5
},
{
"name":"BarTag",
"id":4
}
]
},
"question":"Question?"
}
正如你所看到的,问题在于结构如&#34;答案&#34;:{&#34;答案&#34;:[(...)]}
是否可以选择将其序列化为像&#34;答案&#34;等结构。 :[(...)]没有第二个&#34;答案&#34;标签? 我试图使用&#34; isReference&#34;等属性。但它没有奏效。
答案 0 :(得分:2)
序列化实际上完全符合预期。
我知道它不会完全回答你原来的问题,是否有办法让Json.Net做你想做的事,但你最好的选择就是为你的{{1}设置继承而不是组合。 }。
由于名称表明该类是答案的集合,为什么不将其从AnswersCollection
继承而不是具有此类型的属性?
如果确实无法改变对象的结构,那么您可以采取长期努力的方式,并实施自己的 JsonConverter绝对控制您的属性将如何序列化/反序列化。
您必须将JsonConverterAttribute应用于List<Answer>
属性,以告知Json.Net使用您的自定义序列化程序。
但是,如果可以避免,我强烈建议不采用这种方法。
偏离主题作为旁注:
您应该考虑使用CamelCasePropertyNamesContractResolver 告诉序列化程序在序列化您的属性时使用CamelCasing,因此您不必在属性本身上使用camelCasing:Poll.answers
应拼写为answers
你想遵循常见的命名做法。
答案 1 :(得分:2)
如果您不需要使用序列化进行往返(换句话说,您只需序列化但不需要反序列化),那么获得所需结果的一种简单方法是制作集合类像这样实施IEnumerable<T>
:
class AnswersCollection : IEnumerable<Answer>
{
public List<Answer> answers { get; set; }
public IEnumerator<Answer> GetEnumerator()
{
return answers != null ? answers.GetEnumerator() : new List<Answer>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
这是有效的,因为Json.Net会在序列化过程中自动将实现IEnumerable
的类视为数组。
如果您还需要反序列化,那么您需要更进一步,并执行以下操作之一:
IEnumerable<T>
的构造函数,如@dbc在下面的评论中所建议的那样; ICollection<T>
或List<T>
@Fabio Salvalai在他的回答中建议。如果您不想更改类,另一种方法是实现自定义JsonConverter
来处理自定义序列化/反序列化。转换器可能看起来像这样:
class CollectionConverter<TCollection, TItem> : JsonConverter where TCollection : new()
{
private string ListPropertyName { get; set; }
public CollectionConverter(string listPropertyName)
{
ListPropertyName = listPropertyName;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(TCollection);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
List<TItem> list = (List<TItem>)typeof(TCollection).GetProperty(ListPropertyName).GetValue(value, null);
JArray array = JArray.FromObject(list);
array.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = JArray.Load(reader);
List<TItem> list = array.ToObject<List<TItem>>();
TCollection collection = new TCollection();
typeof(TCollection).GetProperty(ListPropertyName).SetValue(collection, list);
return collection;
}
}
要使用转换器,您需要将[JsonConverter]
属性添加到Poll类的Collection属性中,如下所示:
class Poll
{
[JsonConverter(typeof(CollectionConverter<AnswersCollection, Answer>), "answers")]
public AnswersCollection answers { get; set; }
[JsonConverter(typeof(CollectionConverter<TagsCollection, Tag>), "tags")]
public TagsCollection tags { get; set; }
public string question { get; set; }
}
然后像往常一样序列化和反序列化。