开发者

C# How do you solve a circular object reference

I've run into what i belive could be a major issue for my code design and i was hoping someone here could explain to me how i would work around the issue.

I have 2 classes which each have a property of the other class creating a circular re开发者_如何学JAVAference. I plan on serializing these classes and using XSLT to format the output but i'm assuming this will fail due to the circular reference.

Example

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

So from this example each book will be in a bookShop and each bookshop will have many books. If i serialize the bookshop it will then serialize each book which then serialize a bookshop and so on round and round. How should i handle this?


Tag TheShop with an attribute to prevent its serialization.

[XmlIgnore] with the default serializer.

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

Probably just a problem with your example, not your real code: Don't use public fields but properties. I think XmlSerializer doesn't even serialize public fields.


Add [XmlIgnore] to the TheShop property to prevent it from being serialized.

You can then set it manually when deserializing.


Best practice would be to have the BookShop class implement an interface (IBookShop) and then have the Book class store the interface not the concrete class. You should also make BookShop into a property in the Book class:

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()
    {
    }
}


If you're going to use System.Xml.Serialization.XmlSerializer, you should decorate TheShop with System.Xml.Serialization.XmlIgnoreAttribute:

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

That is, assuming the BookShop is the root object you wish to serialize. MSDN


First you need to check whether this is really a problem. If you always care about a bookshop when you have a book, and you always care about all the books a bookshop has, then it's perfectly sensible to have the whole graph serialised. This doesn't result in an infinite loop, because the serialisation uses an identifier to indicate a reference to an object already serialised (there is a bug if you do an XML serialisation of a graph with a circular reference in its types, but that's a bug rather than inherent to the problem of serialising XML, as the fact that it can be resolved proves, see Why do I get a "System.StackOverflowException was unhandled " exception when serializing? on that).

So, maybe you don't want to do anything here at all, and you're fine as you are.

Otherwise, the question is - just what do you want to serialise? Most suggestions so far have been to not serialise the TheShop property. This could be fine, or it may be useless if you will need to later access that shop.

If you have some sort of identifier (id number, uri) for each shop, then you could perhaps memoise - access to TheShop looks first at whether a private _theShop is null, and if it is, loads the relevant object into _theShop based on that identifier. Then you just need to serialise the identifier, not the full object.

Finally, if you are using XSLT to format the output to some other specification (whether XHTML for display, or something else) you may find it simpler just to roll your own XML serialisation. While this is a more complicated task in many ways, the fact that the XML produced by serialisation isn't particularly convenient for reformatting for display may mean that overall it's simpler this way. Indeed, if this is your only reason for serialising (you will never deserialise from the XML produced) then it may be much easier, as you need only consider what the XML for display needs, and not worry about anything else. Hence serialising may not be the best approach at all, but simply a ToXml() method, or a WriteBookToXml() method in another class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜