I use a simple class that is serializable. It has a constructor for the deserialization:
protected MyClass(SerializationInfo info, StreamingContext context)
Now both methods get called before the constructor gets called
No, the order is:
And how can a (non-static) method be called before any constructor has been executed?
Because it cheats and lies; it doesn't create the object with the constructor; no - really. It uses FormatterServices.GetUninitializedObject
to allocate vanilla empty space. And then if there is a custom deserialization constructor it invokes the constructor over the top of that object. Nasty. Like this, basically:
var obj = FormatterServices.GetUninitializedObject(typeof(MyClass));
var ctor = obj.GetType().GetConstructor(
BindingFlags.Instance | BindingFlags.Public| BindingFlags.NonPublic,
null,
new[] { typeof(SerializationInfo), typeof(StreamingContext) },
null);
ctor.Invoke(obj, new object[2]);
IMO they probably should have made this a second method on the ISerializable
interface, but for whatever reason: they didn't. A shame really: that would have made it more honest, and avoided people needing to remember to implement the custom constructor.
Example output:
.ctor: MyClass
> serializing
OnSerializingMethod: MyClass
GetObjectData: MyClass
OnSerializedMethod: MyClass
< serializing
> deserializing
OnDeserializingMethod: MyClass
.ctor: MyClass
OnDeserializedMethod: MyClass
< deserializing
Example code:
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
class MyClass : ISerializable
{
public MyClass() { Trace(); }
protected MyClass(SerializationInfo info, StreamingContext context) { Trace(); }
public void GetObjectData(SerializationInfo info, StreamingContext context) { Trace(); }
void Trace([CallerMemberName] string caller = null)
{
System.Console.WriteLine("{0}: {1}", caller, GetType().Name);
}
[OnDeserializing()]
internal void OnDeserializingMethod(StreamingContext context) { Trace(); }
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context) { Trace(); }
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context) { Trace(); }
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context) { Trace(); }
static void Main()
{
using (var ms = new MemoryStream())
{
var orig = new MyClass();
var ser = new BinaryFormatter();
System.Console.WriteLine("> serializing");
ser.Serialize(ms, orig);
System.Console.WriteLine("< serializing");
ms.Position = 0;
System.Console.WriteLine("> deserializing");
ser.Deserialize(ms);
System.Console.WriteLine("< deserializing");
}
}
}
[OnDeserializing] Indicates a method to be called just before deserialization [OnDeserialized] Indicates a method to be called just after deserialization
An [OnDeserializing] method acts as a pseudoconstructor for deserialization, and it is useful for initializing fields excluded from serialization:
[OnDeserializing] and [OnDeserialized] Deserialization bypasses all your normal constructors as well as field initializers. This is of little consequence if every field partakes in serialization, but it can be problematic if some fields are excluded via [NonSerialized].
I took this text from Albahari book C# 5.0 in nutshell page 713 check it out online a lot of example and description about your problem.
Thanks
The order of the calls depend on wether the object is the root of the serialized tree or some member of an object, which is also serialized in the same object graph. I get the following output with the extended example provided by Marc Gravell:
SerRoot.ctor
SerMember.ctor
> serializing
SerRoot.OnSerializingMethod
GetObjectData
SerMember.OnSerializingMethod
SerMember.GetObjectData
SerRoot.OnSerializedMethod
SerMember.OnSerializedMethod
< serializing
> deserializing
SerRoot.OnDeserializingMethod
SerMember.OnDeserializingMethod
SerMember.OnDeserializedMethod
SerMember.ctor(info, context)
SerRoot.ctor(info, context)
SerRoot.OnDeserializedMethod
< deserializing
Notice that in deserialization SerMember.ctor is called after SerMember.OnDeserializedMethod! This is the code:
static void Main(string[] args)
{
using (var ms = new MemoryStream())
{
var orig = new SerRoot();
var ser = new BinaryFormatter();
System.Console.WriteLine("> serializing");
ser.Serialize(ms, orig);
System.Console.WriteLine("< serializing");
ms.Position = 0;
System.Console.WriteLine("> deserializing");
ser.Deserialize(ms);
System.Console.WriteLine("< deserializing");
}
}
[Serializable]
class SerRoot : ISerializable
{
public SerMember m;
public SerRoot()
{
System.Console.WriteLine("SerRoot.ctor");
m = new SerMember();
}
protected SerRoot(SerializationInfo info, StreamingContext context)
{
System.Console.WriteLine("SerRoot.ctor(info, context)");
m = info.GetValue("m", typeof(SerMember)) as SerMember;
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
System.Console.WriteLine("GetObjectData");
info.AddValue("m", m);
}
[OnDeserializing()]
internal void OnDeserializingMethod(StreamingContext context) { System.Console.WriteLine("SerRoot.OnDeserializingMethod"); }
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context) { System.Console.WriteLine("SerRoot.OnDeserializedMethod"); }
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context) { System.Console.WriteLine("SerRoot.OnSerializingMethod"); }
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context) { System.Console.WriteLine("SerRoot.OnSerializedMethod"); }
}
[Serializable]
class SerMember : ISerializable
{
string text;
public SerMember()
{
System.Console.WriteLine("SerMember.ctor");
text = "test";
}
protected SerMember(SerializationInfo info, StreamingContext context)
{
System.Console.WriteLine("SerMember.ctor(info, context)");
text = info.GetString("text");
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
System.Console.WriteLine("SerMember.GetObjectData");
info.AddValue("text", text);
}
[OnDeserializing()]
internal void OnDeserializingMethod(StreamingContext context) { System.Console.WriteLine("SerMember.OnDeserializingMethod"); }
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context) { System.Console.WriteLine("SerMember.OnDeserializedMethod"); }
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context) { System.Console.WriteLine("SerMember.OnSerializingMethod"); }
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context) { System.Console.WriteLine("SerMember.OnSerializedMethod"); }
}