How do you serialize object references?

F

films

I understand the concept.

Serialization of a class will add all the sub-objects of the class to
the stream if there are also serializible.

So say I have:

[Serialize]
class Author
{
public string Name = string.empty;
void Author(author)
{
Name = author;
}
}

[Serialize]
class Book
{
public Author author = null;
void Book(string authorname)
{
author = new Author(authorname);
}
}

void Main()
{
Book mybook = new book("John Smith");
// here I would open a stream and serialize the book collection.
}


Now, when I read back the stream and populate the book collection there
is indeed a reference to the author, since it saved the information,
however, what if I tried this:

void Main()
{
Book mybook = new book("John Smith");
Book mybook2 = mybook;
// here I would open a stream and serialize the book collection.
// then I read back both books, which should both contain a ref
// to the single author entry.
}

upon reading back the books from the stream there are TWO copies of
Author, not just a reference to the single entry I started with

So, if I change the author name on one book, it will not update the
second book.

Is there a way to have the object's runtime references persist between
sessions given that they are saved/serialized to a stream and read
back?

It would seem that the serialization process copies each object
reference by value to the stream when serializing. Is there a work
around or is this something beyond the capabilites of serialization?
 
M

Marcos Stefanakopolus

The SoapFormatter and BinaryFormatter classes support serializing and
deserializing an entire object graph. In your case, the graph would consist
of multiple books with references to the same author. The built-in
serialization/deserialization logic detects and handles this sort of
situation. The problem you're running into is that you are serializing your
books separately from your authors, thus giving the serialization logic no
point to detect that one of your authors is shared among multiple books.

My solution to this sort of situation is typically, at the application
level, to create a "UserDocument" class which is a simple container for all
the data that the user might be working with in the application. In your
case it would be something like:

[Serializable]
class UserDocument {
Books[] books;
Authors[] authors;
}

That's the thing you serialize, thus allowing the formatter to analyze your
books and your authors together, to detect the re-use of an author, and save
him only once. (and, even better, recreate him only once during
deserialization).

The sequence of actions your application then takes is something like this:

1. Create a UserDocument object at app load time, in response to file->new,
etc.:
myDocument = new UserDocument();
2. the user does stuff, turning myDocument into something worth saving.
3. BinaryFormatter b = new BinaryFormatter(new
Stream(mySaveFileDialog.Filename));
b.Serialize(theUserDocument);

The only other caveat I would offer, although you didn't ask explicitly, is
to make sure that if your Book and Author types use events to communicate
with each other and with your application's UI, make sure to mark the event
fields with [field:NonSerialized]; frequently the event objects your data
objects are using contain refererences to non-serializable classes
(typically, your main Form class), by virtue of holding references to the
event handlers that have subscribed to them. If the Serialize() method
encounters one of these, it will throw a run-time error because you're
trying to serialize a non-serializable class. Then, of course, you'll need
to create a mechanism to re-subscribe the event proper event handlers when
the object graph is restored from its serialized form. There's an interface
you implement in order to get a callback after deserialization happens so
you can fix up the values of any non-serialized fields, IDeserialization or
something like that, but my reference books are not where I am right now so
you'll have to look that one up for yourself.

I understand the concept.

Serialization of a class will add all the sub-objects of the class to
the stream if there are also serializible.

So say I have:

[Serialize]
class Author
{
public string Name = string.empty;
void Author(author)
{
Name = author;
}
}

[Serialize]
class Book
{
public Author author = null;
void Book(string authorname)
{
author = new Author(authorname);
}
}

void Main()
{
Book mybook = new book("John Smith");
// here I would open a stream and serialize the book collection.
}


Now, when I read back the stream and populate the book collection there
is indeed a reference to the author, since it saved the information,
however, what if I tried this:

void Main()
{
Book mybook = new book("John Smith");
Book mybook2 = mybook;
// here I would open a stream and serialize the book collection.
// then I read back both books, which should both contain a ref
// to the single author entry.
}

upon reading back the books from the stream there are TWO copies of
Author, not just a reference to the single entry I started with

So, if I change the author name on one book, it will not update the
second book.

Is there a way to have the object's runtime references persist between
sessions given that they are saved/serialized to a stream and read
back?

It would seem that the serialization process copies each object
reference by value to the stream when serializing. Is there a work
around or is this something beyond the capabilites of serialization?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top