Сериализация коллекции объектов (List) с связями в XML

Я столкнулся с проблемой сериализации объектов с связями в XML. Допустим у меня есть:

[Serializable]
public class User
{
    public string Name { get; set; }
    public int UserId { get; set; }
    public ICollection<Catalog> Catalogs { get; set; }

    public User()
    {
        Catalogs = new List<Catalog>();
    }
}

Далее

[Serializable]
public class File
{
    public int FileId { get; set; }
    public string Name { get; set; }
    public int CatalogId { get; set; }
    public Catalog Catalog { get; set; }
}

И

[Serializable]
public class Catalog
{
    public int CatalogId { get; set; }
    public string Name { get; set; }
    public int? RootCatalogId { get; set; }
    public Catalog RootCatalog { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
    public ICollection<File> Files { get; set; }
    public Catalog()
    {
        Files = new List<File>();
    }
}

Далее Имитирую заполнение:

        var user = new User()
        {
            UserId = 1,
            Name = "first"
        };


        var catalog1 = new Catalog()
        {
            CatalogId = 1,
            Name = "first",
            User = user,
            UserId = user.UserId
        };

        var catalog2 = new Catalog()
        {
            CatalogId = 2,
            Name = "second",
            User = user,
            UserId = user.UserId,
            RootCatalog = catalog1,
            RootCatalogId = catalog1.CatalogId
        };

        user.Catalogs.Add(catalog1);
        user.Catalogs.Add(catalog2);

        var file1 = new File() {
            Name = "first",
            FileId = 1,
            Catalog=catalog1,
            CatalogId=catalog1.CatalogId
        };

        catalog1.Files.Add(file1);


        var file2 = new File()
        {
            Name = "second",
            FileId = 2,
            Catalog = catalog2,
            CatalogId = catalog2.CatalogId
        };
        catalog2.Files.Add(file2);

Далее сериализация:

            XmlSerializer xml = new XmlSerializer(typeof(User));

            TextWriter writer = new StreamWriter("xmltest.xml");

            xml.Serialize(writer,user);

И вуоля ошибка: введите сюда описание изображения


Ответы (1 шт):

Автор решения: Ulysses

Я бы обратил внимание на три момента.

Во-первых, нельзя сериализовать интерфейсы. Зачем вам свойство типа ICollection, когда вы все равно его инициализируете списком? Сделайте это свойство типа List<T>.

Во-вторых, сериализация не производится при наличии циклических ссылок. У вас же юзер ссылается на каталоги, а каталоги на юзера. Каталог ссылается на рут, а он на свои каталоги. Каталог ссылается на файлы, а файл на каталог. Не нужно сериализовать свойства со ссылками на эти объекты. При десериализации придется восстанавливать ссылки по ID. Как-то так:

[Serializable]
public class User
{
    public string Name { get; set; }
    public int UserId { get; set; }
    public List<Catalog> Catalogs { get; set; }

    public User()
    {
        Catalogs = new List<Catalog>();
    }
}

[Serializable]
public class File
{
    public int FileId { get; set; }
    public string Name { get; set; }
    public int CatalogId { get; set; }

    [XmlIgnore]
    public Catalog Catalog { get; set; }
}

[Serializable]
public class Catalog
{
    public int CatalogId { get; set; }
    public string Name { get; set; }
    public int? RootCatalogId { get; set; }

    [XmlIgnore]
    public Catalog RootCatalog { get; set; }

    public int UserId { get; set; }

    [XmlIgnore]
    public User User { get; set; }

    public List<File> Files { get; set; }

    public Catalog()
    {
        Files = new List<File>();
    }
}

И в-третьих, вы используете System.IO, в котором уже есть класс File. Я бы переименовал ваш собственный класс File или, обращаясь к нему, явно указывал пространство имен. Пока, по-видимому, ваш класс File и класс с методом, где происходит сериализация, находятся в одном пространстве имен. В этой ситуации все будет работать. Но я бы поправил во избежание дальнейших коллизий.

→ Ссылка