Сериализация коллекции объектов (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 шт):
Я бы обратил внимание на три момента.
Во-первых, нельзя сериализовать интерфейсы. Зачем вам свойство типа 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 и класс с методом, где происходит сериализация, находятся в одном пространстве имен. В этой ситуации все будет работать. Но я бы поправил во избежание дальнейших коллизий.
