Thursday, October 27, 2011

Serialization lost

Just a side note.

When an object is been deserialized by IFormatter, no constructors are called*! So if you have any fields marked as [NonSerialized] that are initilized in constructors or inline, they would not be initialized at all!

Consider the following example:

[Serializable]
public class Test
{
 public Test()
 {
  Console.WriteLine("Inside ctor");
 }

 [NonSerialized]
 private readonly string _nonSerizlied = "Non serialized";

 private readonly string _serizlied = "Serialized";

 public override string ToString()
 {
  return string.Format("NonSerizlied: {0}, Serizlied: {1}"_nonSerizlied_serizlied);
 }
}
 
 
static void Main(string[] args)
{
 Test test = new Test();

 Console.WriteLine(test);

 IFormatter formatter = new BinaryFormatter();
 using (var stream = new MemoryStream())
 {

  formatter.Serialize(stream, test);

  stream.Position = 0;

  test = (Test) formatter.Deserialize(stream);

  Console.WriteLine(test);
 }
} 
 
The output will be:

Inside ctor
NonSerizlied: Non serialized, Serizlied: Serialized
NonSerizlied: , Serizlied: Serialized

So _nonSerizlied  field is not initialized at all and constructor is not called.

* If a type realized ISerializable, the serialization constructor will be called, but the default one will be not as well.


 

Wednesday, October 26, 2011

Initialization trick

You all now the cool syntax sugar for object initialization in C#:

var item = new Item { Age = 5 };


Also there are sugar for collection initialization:

var items = new List<Item> { new Item { Age = 5 } };

And, of course, we could mix these two cases:
class ItemContainer
{
    public List<Item> Items{get;set;}
} 

// ...

var itemContainer = new ItemContainer {
   Items = new List<Item> {new Item { Age = 5 }}
};

But there is one rarely used case that is even cooler. If  ItemContainer.Items is ICollection and it is created in constructor:
class ItemContainer
{
   public ItemContainer()
   {
      Items = new List<Item>();
   } 
  
   public List<Item> Items{get;set;}
} 
 
Than you can add elements to the Items collection without 'new' construction:
var itemContainer = new ItemContainer {
   Items = { new Item { Age = 5 } }
};

This code will be ILed as:

IL_0000: newobj ItemContainer..ctor
IL_0005: stloc.1 
IL_0006: ldloc.1 
IL_0007: callvirt ItemContainer.get_Items  
IL_000C: newobj Item..ctor
IL_0011: stloc.2 
IL_0012: ldloc.2 
IL_0013: ldc.i4.1 
IL_0014: callvirt Item.set_Age
IL_0019: ldloc.2 
IL_001A: callvirt System.Collections.Generic.List<Item>.Add

So there is no constructions of Items, just single method 'Add'.
The same is applicable for Expressions as well.