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 second
answers
是AnswersCollection类中的变量名——由于正在序列化Poll类,所以可以同时获得这两个变量——没有可以设置的标志来改变这一点……这是因为classes@Bret我知道这一点,我希望避免只包含变量或类的名称,而不包含I忽略它的内容,因为所有集合类都封装了一些方法。实际上,对于
answerscolection:IEnumerable@dbc Nice,我没有考虑过,但它是有效的。我会将这些信息添加到我的答案中。谢谢。实际上,对于
answerscolection:IEnumerable@dbc Nice,我没有考虑过,但它是有效的。我会添加它请参考我的答案。谢谢。