C # xml serializer - сериализует производные объекты - PullRequest
3 голосов
/ 01 февраля 2011

Я хочу сериализовать следующее:

[Serializable]
[DefaultPropertyAttribute("Name")]
[XmlInclude(typeof(ItemInfo))]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfo
{
    public string name;

    [XmlArray("Items"), XmlArrayItem(typeof(ItemInfo))]
    public ArrayList arr;

    public ItemInfo parentItemInfo;
}

[Serializable]
[XmlInclude(typeof(ItemInfo))]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfoA : ItemInfo
{
...
}

[Serializable]
[XmlInclude(typeof(ItemInfo))]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfoB : ItemInfo
{
...
}

Класс itemInfo описывает контейнер, который может содержать другие объекты itemInfo в списке массивов, parentItemInfo описывает, который является родительским контейнероминформации об элементе.

Поскольку ItemInfoA и ItemInfoB являются производными от ItemInfo, они также могут быть членами списка массивов и parentItemInfo, поэтому при попытке сериализации этих объектов (которые могутудерживать много объектов в иерархии) это не сработало за исключением

IvvalidOperationException.`there was an error generating the xml file `

Мой вопрос:

Какие атрибуты мне нужны, чтобы добавить класс ItemInfo, чтобы он был сериализуем?

Примечание. Исключением является только то, что ItemInfo [A] / [B] инициализируется с помощью parentItemInfo или arrayList.

Помогите пожалуйста!

Спасибо!

1 Ответ

8 голосов
/ 01 февраля 2011

С отредактированным вопросом, похоже, у вас есть цикл.Обратите внимание, что XmlSerializer - это сериализатор tree , а не сериализатор graph , поэтому произойдет сбой.Обычное исправление здесь - отключение обхода вверх:

[XmlIgnore]
public ItemInfo parentItemInfo;

Обратите внимание, что вам, конечно, придется вручную исправить родителей после десериализации.

В отношении исключения - вам нужно посмотреть наInnerException - это, вероятно, говорит вам именно это, например, в вашей (catch ex):

while(ex != null) {
    Debug.WriteLine(ex.Message);
    ex = ex.InnerException;
}

Я предполагаю, что это действительно:

"Циркулярная ссылка былаобнаружен при сериализации объекта типа ItemInfoA. "


Больше обычно в дизайне, честно говоря, что (открытые поля, ArrayList, настраиваемые списки) - плохая практика;вот более типичная перезапись , которая ведет себя одинаково :

[DefaultPropertyAttribute("Name")]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfo
{
    [XmlElement("name")]
    public string Name { get; set; }

    private readonly List<ItemInfo> items = new List<ItemInfo>();
    public List<ItemInfo> Items { get { return items; } }

    [XmlIgnore]
    public ItemInfo ParentItemInfo { get; set; }
}
public class ItemInfoA : ItemInfo
{
}
public class ItemInfoB : ItemInfo
{
}

в соответствии с просьбой, вот общая (не специфичная для вопроса) иллюстрация рекурсивной постановки родителей в улье(для ударов я использую первый в глубине кучи; для первого - просто поменяйте Stack<T> на Queue<T>; я стараюсь избегать рекурсии на основе стека в этих сценариях):

public static void SetParentsRecursive(Item parent)
{
    List<Item> done = new List<Item>();
    Stack<Item> pending = new Stack<Item>();
    pending.Push(parent);
    while(pending.Count > 0)
    {
        parent = pending.Pop();
        foreach(var child in parent.Items)
        {
            if(!done.Contains(child))
            {
                child.Parent = parent;
                done.Add(child);
                pending.Push(child);
            }                
        }
    }
}
...