Why can't the 'NonSerialized' attribute be used at the class level? How to prevent serialization of a class?

StackOverflow https://stackoverflow.com/questions/2467376

Question

I have a data object that is deep-cloned using a binary serialization. This data object supports property changed events, for example, PriceChanged.

Let's say I attached a handler to PriceChanged. When the code attempts to serialize PriceChanged, it throws an exception that the handler isn't marked as serializable.

My alternatives:

  • I can't easily remove all handlers from the event before serialization
  • I don't want to mark the handler as serializable because I'd have to recursively mark all the handlers dependencies as well.
  • I don't want to mark PriceChanged as NonSerialized - there are tens of events like this that could potentially have handlers. EDIT: Another reason why I can't do this is because the data classes (and hence the events) are generated and I don't have direct control over the generation code. Ideally, the generation code would just mark all events as NonSerialized.
  • Ideally, I'd like .NET to just stop going down the object graph at that point and make that a 'leaf'. So why doesn't .NET allow an entire class to be marked as NonSerialized?

--

I finally worked around this problem by making the handler implement ISerializable and doing nothing in the serialize constructor/ GetDataObject method. But, the handler still is serialized, just with all its dependencies set to null - so I had to account for that as well.

Is there a better way to prevent serialization of an entire class? That is, one that doesn't require accounting for the null dependencies?

Was it helpful?

Solution

While I tend to disagree with the approach (I would simply mark the events as NonSerialized, regardless of how many there are) you could probably do this using serialization surrogates.

The idea is that you create an object that implements ISerializationSurrogate and basically does what you're already doing - nothing in the GetObjectData and SetObjectData methods. The difference is that you would be customizing the serialization of the delegate, not the class containing it.

Something like:

class DelegateSerializationSurrogate : ISerializationSurrogate {
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
        // do nothing
    }
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context) {
        // do nothing
        return null;
    }
}

Then you register this with the formatter using the procedures outlined in this MSDN column. Then whenever the formatter encounters a delegate, it uses the surrogate instead of serializating the delegate directly.

OTHER TIPS

...there are tens of events...

Personally, then I'd just add the non-serialized markers, which for field-like events is most easily done via:

[field: NonSerialized]
public event SomeEventType SomeEventName;

(you don't need to add a manual backing delegate)

What are your serialization requirements exactly? BinaryFormatter is in many ways the least friendly of the serializers; the implications on events are a bit ugly, and it is very brittle if stored (IMO it is only really suitable for transport, not for storage).

However; there are plenty of good alternatives that would support most common "deep clone" scenarios:

  • XmlSerializer (but limited to public members)
  • DataContractSerializer / NetDataContractSerializer
  • protobuf-net (which includes Serializer.DeepClone for this purpose)

(note that in most of those serialization support would require extra attributes, so not much different to adding the [NonSerialized] attributes in the first place!)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top