ENTERPRISE

Programming .NET Components : Serialization and Persistence - Automatic Serialization

12/27/2012 2:10:02 AM

.NET implements the automatic serialization of objects by means of reflection, a simple and elegant technique that uses metadata exposed by every .NET component. .NET can capture the value of every one of an object's fields and serialize it to memory, to a file, or to a network connection. .NET also supports automatic deserialization: .NET can create a new object, read its persisted field values, and, using reflection, set the values of its fields. Because reflection can access private fields, including base-class fields, .NET can take a complete snapshot of the state of an object during serialization and perfectly reconstruct that state during deserialization. Another advantage of reflection-based serialization is that the code used by .NET is completely general-purpose—the state of every .NET type can be read or set using reflection.

.NET serializes the object state into a stream. A stream is a logical sequence of bytes, independent of any particular medium (file, memory, communication port, or other resource). This extra level of indirection means that you can use the same serialization infrastructure with any medium, simply by selecting an appropriate stream type. The various stream types provided by .NET all derive from the abstract class Stream, defined in the System.IO namespace. Although you need a Stream instance to serialize and deserialize an object, there is usually no need to interact explicitly with the methods and properties of the Stream itself.

.NET serialization is object-based. As a result, only instance fields are serialized. Static fields are excluded from serialization.


1. The Serializable Attribute

By default, user-defined types (classes and structs) aren't serializable. The reason is that .NET has no way of knowing whether a reflection-based dump of the object state to a stream makes sense. Perhaps the object members have some transient value or state (such as an open database connection or communication port). If .NET simply serialized the state of such an object, when you constructed a new object by deserializing it from the stream you would end up with a defective object. Consequently, serialization can be performed only with the developer's consent.

Enumerations are always serializable.


To indicate to .NET that instances of your class are serializable, you can add the Serializable attribute to your class definition. For example:

    [Serializable]
    public class MyClass
    {
        public string SomeString;
        public int SomePublicNumber;
        int m_SomePrivateNumber;
        /* Methods and properties */
    }

In most cases, decorating a user-defined type definition with the Serializable attribute is all you need to do. If the class has member variables that are complex types themselves, .NET automatically serializes and deserializes these members as well:

    [Serializable]
    public class MyOtherClass
    {...}

    [Serializable]
    public class MyClass
    {
        MyOtherClass m_Obj;
        /* Methods and properties */
    }

The result is recursive iteration over an object and all its contained objects. The object can be the root of a huge graph of interconnected objects, as shown in Figure 1.

Figure 1. .NET serialization traverses the entire object graph

Regardless of its depth, .NET captures the entire state of any graph and serializes it. The recursive traversal algorithm used by .NET is smart enough to detect cyclic references in the graph, tagging objects it has already visited and thereby avoiding processing the same object twice. This approach allows .NET to serialize complex data structures such as doubly linked lists.

2. Non-Serializable Members

When a class is serializable, .NET insists that all its member variables be serializable as well. If it discovers a non-serializable member, it throws an exception of type SerializationException during serialization. However, what if the class or a struct has a member that can't be serialized? That type will not have the Serializable attribute and will preclude the containing type from being serialized. Commonly, that non-serializable member is a reference type that requires some special initialization. The solution to this problem requires marking such a member as non-serializable and taking a custom step to initialize it during deserialization.

To allow a serializable type to contain a non-serializable type as a member variable, you need to mark the member with the NonSerialized field attribute:

    public class MyOtherClass
    {...}

    [Serializable]
    public class MyClass
    {
    
       [NonSerialized]
       MyOtherClass m_Obj;
       /* Methods and properties */
    }

When .NET serializes a member variable, it first reflects it to see whether it has the NonSerialized attribute. If so, .NET ignores that variable and simply skips over it. This allows you to preclude from serialization even serializable types:

    [Serializable]
    public class MyClass
    {
    
       [NonSerialized]
					int m_Number;
    }

However, when .NET deserializes the object, it initializes each non-serializable member variable to the default value for that type (null for all reference types). It's then up to you to provide code to initialize the variables to their correct values. To that end, the object needs to know when it's being deserialized. The notification takes place by implementing the interface IDeserializationCallback, defined in the System.Runtime.Serialization namespace:

    public interface IDeserializationCallback
    {
       void OnDeserialization(object sender);
    }

IDeserializationCallback's single method, OnDeserialization( ), is called after .NET has deserialized the object, allowing it to perform the required custom initialization steps. The sender parameter is ignored and is always set to null by .NET. Example 1 demonstrates how you can implement IDeserializationCallback. In the example, the class MyClass has a database connection as a member variable. The connection object (SqlConnection) isn't a serializable type and so is marked with the NonSerialized attribute. MyClass creates a new connection object in its implementation of OnDeserialization( ), because after deserialization the connection member is set to its default value of null. MyClass then initializes the connection object by providing it with a connection string and opens it.

Example 1. Deserialized event using IDeserializationCallback
using System.Runtime.Serialization;

[Serializable]
public class MyClass : IDeserializationCallback
{
   [NonSerialized]
   IDbConnection m_Connection;
   string m_ConnectionString;

   public void OnDeserialization(object sender)
   {
      Debug.Assert(m_Connection == null);
      m_Connection = new SqlConnection(  );
      m_Connection.ConnectionString = m_ConnectionString;
      m_Connection.Open(  );
   }
   /* Other members */
}

You can't initialize class members marked with the readonly directive in OnDeserialization( )—such members can only be initialized in a constructor.


On non-sealed classes, it is important to use either implicit interface implementation of IDeserializationCallback and have the base class mark its OnDeserialization( ) method as virtual to allow subclasses to override it. When class hierarchies are involved, you need to call your base-class implementation of OnDeserialization( ), and that requires a non-private implementation:

    [Serializable]
    public class MyBaseClass : IDeserializationCallback
    {
       public virtual void OnDeserialization(object sender)
       {...}
    }
    [Serializable]
    public class MySubClass : MyBaseClass
    {

       public override void OnDeserialization(object sender)
       {
          //Perform custom steps, then:
          base. OnDeserialization(sender);
       }
    }

2.1. Delegates and serialization

All delegate definitions are compiled into serializable classes. This means that when you serialize an object that has a delegate member variable, the internal invocation list of the delegate is serialized too. I believe that this renders delegates inherently non-serializable. There are no guarantees that the target objects in the internal list are serializable, so sometimes the serialization will work and sometimes it will throw a serialization exception. In addition, the object containing the delegate typically does not know or care about the actual state of the delegate. This is especially true when the delegate is used to manage event subscriptions, because the exact number and identities of the subscribers are often transient values that should not be persisted between application sessions.

You should mark delegate member variables as non-serializable, using the NonSerialized attribute:

    [Serializable]
    public class MyClass
    {
       [NonSerialized]
       EventHandler m_MyEvent;
    }

In the case of events, you must also add the field attribute qualifier when applying the NonSerialized attribute:

    [Serializable]
    public class MyPublisher
    {
       [field: NonSerialized]
       public event EventHandler MyEvent;
    }
Other  
 
Video
Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone