C # Как вы решаете круговую ссылку на объект - PullRequest
3 голосов
/ 24 ноября 2010

Я столкнулся с тем, что, как я полагаю, может стать серьезной проблемой для моего дизайна кода, и я надеялся, что кто-то здесь сможет объяснить мне, как я буду обходить эту проблему.

У меня есть 2 класса, каждый из которыхиметь свойство другого класса, создающего циклическую ссылку.Я планирую сериализовать эти классы и использовать XSLT для форматирования вывода, но я предполагаю, что это не удастся из-за циклической ссылки.

Пример

public class Book
{
  public BookShop TheShop = new BookShop();
}
public class BookShop
{
  list<Book> Books = new list<Book>();
}

Так что из этого примера каждая книга будетбыть в книжном магазине, и у каждого книжного магазина будет много книг.Если я сериализирую книжный магазин, он будет сериализовать каждую книгу, которая затем сериализует книжный магазин и так далее.Как мне справиться с этим?

Ответы [ 5 ]

6 голосов
/ 24 ноября 2010

Тег TheShop с атрибутом для предотвращения его сериализации.

[XmlIgnore] с сериализатором по умолчанию.

http://www.codeproject.com/KB/XML/GameCatalog.aspx

Вероятно, проблема в вашем примере, а не в реальном коде: не используйте открытые поля, а свойства.Я думаю, что XmlSerializer даже не сериализует открытые поля.

1 голос
/ 24 ноября 2010

Рекомендуется, чтобы класс BookShop реализовывал интерфейс (IBookShop), а затем класс Book сохранял интерфейс, а не конкретный класс. Вы также должны сделать BookShop свойством в классе Book:

public class Book
{
    public Book(IBookShop bookShop)
    {
        TheStop = bookShop;
    }
    [XmlIgnore]
    public IBookShop TheShop { get; set; }
}
public interface IBookShop 
{
    void SomeMethod();
}
public class BookShop : IBookShop
{
    list<Book> Books = new list<Book>();
    public void SomeMethod()
    {
    }
}
1 голос
/ 24 ноября 2010

Добавьте [XmlIgnore] к свойству TheShop, чтобы предотвратить его сериализацию.

Вы можете установить его вручную при десериализации.

0 голосов
/ 24 ноября 2010

Сначала вам нужно проверить, действительно ли это проблема. Если вы всегда заботитесь о книжном магазине, когда у вас есть книга, и вы всегда заботитесь обо всех книгах, которые есть в книжном магазине, то вполне разумно сериализовать весь график. Это не приводит к бесконечному циклу, потому что сериализация использует идентификатор, чтобы указать ссылку на объект, уже сериализованный (есть ошибка, если вы делаете сериализацию XML графа с циклической ссылкой в ​​его types , но это проблема, а не присущая проблеме сериализации XML, о чем свидетельствует ее решение, см. Почему я получаю исключение "System.StackOverflowException ishandled" при сериализации? на что).

Так что, может быть, вы вообще не хотите здесь ничего делать, и вы в порядке, как и вы.

В противном случае вопрос - что вы хотите сериализовать? До сих пор большинство предложений заключалось в том, чтобы не сериализовать свойство TheShop. Это может быть хорошо, или это может быть бесполезно, если вам понадобится позднее получить доступ к этому магазину.

Если у вас есть какой-то идентификатор (номер идентификатора, uri) для каждого магазина, то, возможно, вы могли бы вспомнить - доступ к TheShop сначала проверяет, является ли приватный _theShop нулевым, и, если это так, загружает соответствующий объект в _theShop на основе этого идентификатора. Тогда вам просто нужно сериализовать идентификатор, а не полный объект.

Наконец, если вы используете XSLT для форматирования вывода в соответствии с какой-либо другой спецификацией (будь то XHTML для отображения или что-то еще), вам может оказаться проще просто свернуть собственную сериализацию XML. Хотя это во многих отношениях более сложная задача, тот факт, что XML, созданный сериализацией, не особенно удобен для переформатирования для отображения, может означать, что в целом это проще. Действительно, если это ваша единственная причина сериализации (вы никогда не десериализовываете из созданного XML), тогда это может быть намного проще, так как вам нужно только рассмотреть, что нужно для отображения для XML, и не беспокоиться ни о чем другом. Следовательно, сериализация может быть не лучшим подходом, а просто методом ToXml() или WriteBookToXml() в другом классе.

0 голосов
/ 24 ноября 2010

Если вы собираетесь использовать System.Xml.Serialization.XmlSerializer, вам следует украсить TheShop с помощью System.Xml.Serialization.XmlIgnoreAttribute:

public class Book
{
  [System.Xml.Serialization.XmlIgnore]
  public BookShop TheShop;
}

То есть, если BookShop является корневым объектом, который вы хотите сериализовать. 1009 * MSDN *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...