Events and BinaryFormatter serialization in .NET

Serialization in .NET world is not straightforward. For years we've been told to use XmlSerializer, but it has its limitations. It is unable to serialize anything but the public properties/fields, it cannot deal with interfaces in most of the circumstances (specific collection interfaces being the only notable exception) etc. Something that has been used as an alternative for years is SoapFormatter, but it is also far from ideal, most importantly because it cannot handle generic types. This renders it almost useless for any practical .NET application, developed nowadays.

The limitations of XmlSerializer can be overcome by implementing parts of the serialization by hand. However this effectively kills the whole idea of "automated CLR serialization free of charge", which is one of the reasons people use such frameworks as .NET. Our only solution, short of rolling our own serializer, is, at present, BinaryFormatter. It is capable of inspecting almost any objects and only quite unusual structures with circular references can actually break it. So far the only disadvantage of it I've noticed is the fact that it is, as the name implies, binary. This doesn't allow one to inspect the generated output by hand, which is a handicap in some situations. The positive side of it is, of course, reduced size and speed.

One potential pitfall, which awaits BinaryFormatter adopters, is the presence of events. Events, as you know, are part of the Observer pattern, implemented using some syntactic sugar in C#, VB.NET and other .NET languages. Because BinaryFormatter scans every internal field of the object state, it goes into the internal storage, representing the events, you happened to declare on your class. It then scans the store and tries to serialize all its members. Because you don't control the subscribers of the event, it is most certainly not guaranteed, that they will be represented by serializable objects and the operation will fail. Not to mention, that in most cases you don't want to serialize the consumers of your events anyway.

Fortunately, the solution is simple. For instance, if your class happens to implement INotifyPropertyChanged, you can augment your event in the following way:

  1. public class Test : INotifyPropertyChanged
  2. {
  3.         // [...]
  4.         #region INotifyPropertyChanged Members
  5.  
  6.         [field: NonSerialized]
  7.         public event PropertyChangedEventHandler PropertyChanged;
  8.  
  9.         #endregion
  10.         // [...]
  11. }

The attribute will ensure, that the event is not included in serialization, thus preventing the potential run-time failure.

Topic: 

Comments

Just wanted to say thanks, this blog post helped me solve a problem that was driving me crazy!

Add new comment