3

When using read-only fields in a serializable class, that should not be serialized (or don't need to): How can they be restored? Assume the following piece of code:

[Serializable]
class SerializableClass
{
    [NonSerialized]    
    private readonly object someLock = new object();

    [OnDeserializing]
    private void restore(StreamingContext sc) 
    {
        // cannot one-time-access readonly fields (like in a 
        // constructor or shortcut like above), too sad...

        // someLock = new object();
    }

    // ...
}

I came across this problem having some objects for locking (that are exclusively used for locking) that are always private readonly (and which I think don't have a place in the serialized representation). As a workaround I am asking myself:

  • Should these objects better not be read-only, so that they can be restored?
  • Should I instead include them to be serialized (as long these are only some 'empty objects' anyway)?

But there might be a more general solution for the use of read-only fields, e.g.:

  • Is there a way of implementing a deserializing constructor that gets called (like when implementing ISerializable) without loosing the automatic serialization of the fields?

Thanks a lot in advance.

mvo
  • 1,138
  • 10
  • 18

1 Answers1

0

I think this can be obtained by creating a parameterless constructor in that class and initializing the readonly fields there instead of inline.

If that readonly field does not have the same value, then there is no way you can restore it. (readonly fields can only be set in constructor, and deserialization takes place after).

Added comment in response:

While I would not recommend this, you can set in the OnDeserializing method the readonly field using reflection, if changing your strategy will take too much effort:

typeof(SerializableClass).GetField("someLock", BindingFlags.Instance|BindingFlags.NonPublic).SetValue(this,new object());
Cosmin Vană
  • 1,562
  • 12
  • 28
  • 1
    No, that's not the case as constructors are bypassed when deserializing. – mvo Jan 09 '14 at 01:06
  • 1
    Which serializer are you using ? Binary and DataContract serializers will bypasses the constructor as far as I know. – Cosmin Vană Jan 09 '14 at 01:10
  • 1
    While I would not recommend this, you can set in the OnDeserializing method the readonly field using reflection: typeof(SerializableClass) .GetField("someLock" ,BindingFlags.Instance|BindingFlags.NonPublic) .SetValue(this,new object()); – Cosmin Vană Jan 09 '14 at 01:14
  • I'm using the binary serializing engine right now (whose attributes should also work with the data contract serializer). Is there a drop-in replacement? (btw: I don't see the point in automatically calling the default constructor together with deserializing fields as long this may result in a weird object state; I prefer a dedicated deserialization constructor/method...) – mvo Jan 09 '14 at 01:18
  • Thanks for pointing out reflection can do this. However this smells more of a hack than a proper solution to me. :-) – mvo Jan 09 '14 at 01:20
  • 1
    XmlSerializer calls the constructor with no parameters (which is required), but its purpose is different and perhaps makes sense. Reflection is not necessary a hack. But in this case I would avoid it too. I think you'll probably have to change the code, because the binary serializer calls GetUninitializedObject to create the object, and has no extension point at that level to allow for custom code to be executed. – Cosmin Vană Jan 09 '14 at 01:53