C# 序列化集合类时双重包含对象
我正在尝试序列化类轮询,如下所示:C# 序列化集合类时双重包含对象,c#,json,serialization,json.net,C#,Json,Serialization,Json.net,我正在尝试序列化类轮询,如下所示: class Poll { (...) //methods public AnswersCollection answers { get; set; } public TagsCollection tags { get; set; } public string question { get; set; } } { "answers":{ "answers":[ {
class Poll
{
(...) //methods
public AnswersCollection answers { get; set; }
public TagsCollection tags { get; set; }
public string question { get; set; }
}
{
"answers":{
"answers":[
{
"name":"Foo",
"voteQuantity":45
},
{
"name":"Bar",
"voteQuantity":30
}
]
},
"tags":{
"tags":[
{
"name":"FooTag",
"id":5
},
{
"name":"BarTag",
"id":4
}
]
},
"question":"Question?"
}
正如你所看到的,我有“TagsCollection”和“AnswersCollection”,它们看起来都很相似,所以我只展示其中一个
class AnswersCollection
{
(...) //methods
public List<Answer> answers { get; set; }
}
所有类都有默认的公共构造函数(没有参数),因此JSON.NET在序列化方面没有任何问题
问题在于AnswersCollection(即封装),因此,JSON输出如下所示:
class Poll
{
(...) //methods
public AnswersCollection answers { get; set; }
public TagsCollection tags { get; set; }
public string question { get; set; }
}
{
"answers":{
"answers":[
{
"name":"Foo",
"voteQuantity":45
},
{
"name":"Bar",
"voteQuantity":30
}
]
},
"tags":{
"tags":[
{
"name":"FooTag",
"id":5
},
{
"name":"BarTag",
"id":4
}
]
},
"question":"Question?"
}
如您所见,问题在于类似“answers”的结构:{“answers”:[(…)]}
是否有选项将其序列化为类似“answers”:[(…)]这样的结构,而不使用第二个“answers”标记?
我尝试使用“isReference”之类的属性,但没有成功。序列化实际上正是预期的结果 我知道它不会完全回答您最初的问题,即是否有办法让Json.Net做您想做的事情,但您最好的选择是为您的
AnswersCollection
使用继承而不是合成
既然名称表明该类是答案的集合,为什么不让它从列表继承,以绝对控制属性的序列化/反序列化方式呢
您必须对Poll.answers
属性应用,以告知Json.Net使用自定义序列化程序
然而,如果你能避免的话,我强烈建议你不要采取这种方法
作为旁注离题:
在序列化属性时,应考虑使用A来告诉序列化程序使用CAMELCOPE。因此,您不必在属性本身上使用camelcasting:answers
应该拼写为answers
,如果您想遵循常见的命名实践。序列化实际上正是按照预期的方式进行的
我知道它不会完全回答您最初的问题,即是否有办法让Json.Net做您想做的事情,但您最好的选择是为您的AnswersCollection
使用继承而不是合成
既然名称表明该类是答案的集合,为什么不让它从列表继承,以绝对控制属性的序列化/反序列化方式呢
您必须对Poll.answers
属性应用,以告知Json.Net使用自定义序列化程序
然而,如果你能避免的话,我强烈建议你不要采取这种方法
作为旁注离题:
在序列化您的属性时,您应该考虑使用A来告诉您的序列化程序使用CAMECALL,因此您不必在属性本身上使用CAMECALL:<代码>回答< /代码>应该拼写为“代码>回答< /代码>。如果您想遵循常见的命名惯例, 如果您不需要往返于序列化。(换句话说,您只需要序列化,而不需要反序列化),然后获得所需结果的一种简单方法是让集合类实现
IEnumerable
,如下所示:
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();
}
}
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;
}
}
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; }
}
要使用转换器,您需要向Poll类中的集合属性添加[JsonConverter]
属性,如下所示:
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();
}
}
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;
}
}
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; }
}
类轮询
{
[JsonConverter(类型(CollectionConverter),“答案”)]
公共应答集合应答{get;set;}
[JsonConverter(类型(CollectionConverter),“标记”)]
公共标记集合标记{get;set;}
公共字符串问题{get;set;}
}
然后像往常一样进行序列化和反序列化。如果您不需要重复序列化(换句话说,您只需要序列化而不需要反序列化),那么获得所需结果的一种简单方法是让您的集合类实现IEnumerable
,如下所示:
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();
}
}
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;
}
}
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; }
}
要使用转换器,您需要向Poll类中的集合属性添加[JsonConverter]
属性,如下所示:
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();
}
}
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;
}
}
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; }
}
类轮询
{
[JsonConverter(类型(CollectionConverter),“答案”)]
公共应答集合应答{get;set;}
[JsonConverter(类型(CollectionConverter),“标记”)]
公共标记集合标记{get;set;}
公共字符串问题{get;set;}
}
然后像往常一样进行序列化和反序列化。您看过数据契约了吗?第一个答案
是Poll类中的var名称,第二个answers
是AnswersCollection类中的var名称,因为您正在序列化Poll类,所以您可以同时获得这两个名称,因为没有要设置的标志会改变这…这是因为你的大脑结构classes@Bret我知道这一点,我希望避免只包含变量或类的名称,而不忽略它的内容,因为所有集合类都封装了一些方法。您看过Datacontracts吗?第一个答案是Poll类中的变量名称WTIH——the secondanswers
是AnswersCollection类中的变量名——由于正在序列化Poll类,所以可以同时获得这两个变量——没有可以设置的标志来改变这一点……这是因为classes@Bret我知道这一点,我希望避免只包含变量或类的名称,而不包含I忽略它的内容,因为所有集合类都封装了一些方法。实际上,对于answerscolection:IEnumerable@dbc Nice,我没有考虑过,但它是有效的。我会将这些信息添加到我的答案中。谢谢。实际上,对于answerscolection:IEnumerable@dbc Nice,我没有考虑过,但它是有效的。我会添加它请参考我的答案。谢谢。