【问题标题】:C# How do you solve a circular object referenceC#如何解决循环对象引用
【发布时间】:2011-05-15 03:54:52
【问题描述】:

我遇到了我认为可能是我的代码设计的一个主要问题,我希望这里有人可以向我解释我将如何解决这个问题。

我有 2 个类,每个类都有另一个类的属性,创建循环引用。我计划序列化这些类并使用 XSLT 来格式化输出,但我假设这将由于循环引用而失败。

例子

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

所以在这个例子中,每本书都在一个书店里,每个书店都有很多书。如果我对书店进行序列化,它将对每本书进行序列化,然后再对书店进行序列化,以此类推。我该如何处理?

【问题讨论】:

    标签: c# serialization object


    【解决方案1】:

    使用属性标记TheShop 以防止其序列化。

    [XmlIgnore] 使用默认序列化程序。

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

    可能只是您的示例存在问题,而不是您的真实代码:不要使用公共字段,而是使用属性。我认为XmlSerializer 甚至不序列化公共字段。

    【讨论】:

    • 抱歉一个快速创建的示例,实际代码要详细得多。
    【解决方案2】:

    [XmlIgnore] 添加到TheShop 属性以防止它被序列化。

    然后可以在反序列化时手动设置。

    【讨论】:

      【解决方案3】:

      最佳实践是让 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()
          {
          }
      }
      

      【讨论】:

        【解决方案4】:

        如果你要使用System.Xml.Serialization.XmlSerializer,你应该用System.Xml.Serialization.XmlIgnoreAttribute装饰TheShop

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

        也就是说,假设BookShop 是您希望序列化的根对象。 MSDN

        【讨论】:

        • 这是否基本上告诉序列化程序跳过该属性。没关系,但如果我在不同的时间连载一本书,我就看不到它来自哪家商店。也忘记了 XML 一秒钟我什至可以在我的对象之间进行循环引用吗?听起来对我来说是个坏主意。
        • 是的,它会导致序列化程序跳过该属性(或字段)。对象中的循环引用很好(例如在双向链表中的相邻项之间),因为它们允许您在两个方向上遍历关系。问题是 XML 不像内存中的对象那样具有指针或引用。序列化强制一个层次结构。如果您只需要知道这本书在 哪家 商店,您可以在这本书上使其某些标识属性可序列化: public class Book { public string ShopName { get { return TheShop.Name; } } }
        【解决方案5】:

        首先您需要检查这是否真的是一个问题。如果您在拥有一本书时总是关心书店,并且始终关心书店拥有的所有书籍,那么将整个图序列化是完全明智的。这不会导致无限循环,因为序列化使用标识符来指示对已序列化对象的引用(如果您在其 types,但这是一个错误,而不是序列化 XML 问题所固有的,因为它可以解决的事实证明了这一点,请参阅Why do I get a "System.StackOverflowException was unhandled " exception when serializing?)。

        所以,也许你根本不想在这里做任何事情,你现在就很好。

        否则,问题是 - 你想连载什么?到目前为止,大多数建议都是不要序列化 ​​TheShop 属性。这可能没问题,或者如果您以后需要访问该商店,它可能没用。

        如果您对每家商店都有某种标识符(id 号、uri),那么您也许可以记忆 - 访问 TheShop 首先查看私有 _theShop 是否为空,如果是,则加载根据该标识符将相关对象放入_theShop。然后你只需要序列化标识符,而不是完整的对象。

        最后,如果您使用 XSLT 将输出格式化为其他规范(无论是用于显示的 XHTML 还是其他),您可能会发现滚动您自己的 XML 序列化更简单。虽然这在许多方面是一项更复杂的任务,但序列化生成的 XML 对于重新格式化以进行显示并不是特别方便,这可能意味着总体上这种方式更简单。实际上,如果这是您进行序列化的唯一原因(您永远不会从生成的 XML 中反序列化),那么它可能会容易得多,因为您只需要考虑用于显示的 XML 需要什么,而不必担心其他任何事情。因此,序列化可能根本不是最好的方法,而只是 ToXml() 方法,或者另一个类中的 WriteBookToXml() 方法。

        【讨论】:

          猜你喜欢
          • 2011-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-14
          • 1970-01-01
          • 2012-04-25
          相关资源
          最近更新 更多