Click here to Skip to main content
15,891,900 members
Articles / Programming Languages / C#

A Fast/Compact Serialization Framework

Rate me:
Please Sign up or sign in to vote.
4.85/5 (37 votes)
13 Oct 2010GPL35 min read 283.2K   1.2K   175  
A framework for object serializiation/deserialization that is many times faster and yields a compact output.
/*

OpenNxSerialization Framework
Copyright (C) 2006 - 2008 "NeXtreme Innovations"
[The Next Xtreme in ingenuity]

This program is free software, distributed under the terms of
the GNU General Public License Version 2. See the License file
at the top of the source tree.

*/

//#define DIAGNOSTIC_SIGNATURE

using System;
using System.Collections;
using System.IO;
using System.Text;

using NeXtreme.OpenNxSerialization.IO;
using NeXtreme.OpenNxSerialization.Surrogates;
using System.Runtime.Serialization;
using System.Runtime.Remoting.Messaging;
using System.Diagnostics;
using NeXtreme.OpenNxSerialization.Native.IO;

namespace NeXtreme.OpenNxSerialization.Native.Formatters
{
    /// <summary>
    /// Serializes and deserializes an object, or an entire graph of connected objects, in binary format.
    /// Uses the compact serialization framework to achieve better stream size and cpu time utlization.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The basic idea behind space conservation is that every 'known type' is assigned a 2-byte 
    /// type handle by the system. Native .NET serialization stores the complete type information
    /// with serialized object data, which includes assembly, version and tokens etc. Instead of storing
    /// such information only a type handle is stored, which lets the system uniquely identify 'known types'.
    /// 
    /// A known type is a type that is registered with the <see cref="INxTypeSurrogateSelector"/>. Moreover
    /// surrogate types take care of serializing only the required information. Information related to fields
    /// and attributes is not stored as in case of native serialization.
    /// </para>
    /// <para>
    /// From performance's perspective reflection is avoided by using surrogates for types. A type surrogate
    /// is intimate with the internals of a type and therefore does not need reflection to guess 
    /// object schema.
    /// </para>
    /// For types that are not known to the system the formatter reverts to the default .NET 
    /// serialization scheme.
    /// </remarks>
    public class NxBinaryFormatter : IFormatter, IRemotingFormatter
    {
        private static NxBinaryFormatter msDefault;
        private INxTypeSurrogateSelector mSurrogateSelector;
        private NxSerializationContext mContext;

        /// <summary>
        /// Constructor
        /// </summary>
        public NxBinaryFormatter()
        {
            mSurrogateSelector = NxTypeSurrogateSelectorNative.Default;
            this.mContext = new NxSerializationContext(mSurrogateSelector);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="surrogateSelector"></param>
        public NxBinaryFormatter(INxTypeSurrogateSelector surrogateSelector)
        {
            if (surrogateSelector == null)
                throw new ArgumentNullException("surrogateSelector");
            mSurrogateSelector = surrogateSelector;
            this.mContext = new NxSerializationContext(mSurrogateSelector);
        }

        /// <summary>
        /// returns the default instance of <see cref="NxBinaryFormatter"/>
        /// </summary>
        /// <value>The default instance of <see cref="NxBinaryFormatter"/></value>
        public static NxBinaryFormatter Default
        {
            get
            {
                if (msDefault == null)
                    msDefault = new NxBinaryFormatter();
                return msDefault;
            }
        }

        /// <summary>
        /// Get/Set the associated <see cref="INxTypeSurrogateSelector"/> instance.
        /// </summary>
        /// <value>The surrogate selector</value>
        public INxTypeSurrogateSelector SurrogateSelector
        {
            get { return mSurrogateSelector; }
            set { mSurrogateSelector = value; }
        }

        #region /       IFormatter Members       /

        /// <summary>
        /// Gets or sets the <see cref="SerializationBinder"/> that performs type lookups during deserialization
        /// </summary>
        public SerializationBinder Binder
        {
            get { return mContext.Binder; }
            set { mContext.Binder = value; }
        }

        /// <summary>
        /// Gets or sets the <see cref="StreamingContext"/> used for serialization and deserialization
        /// </summary>
        public StreamingContext Context
        {
            get { return mContext.StreamingContext; }
            set { mContext.StreamingContext = value; }
        }

        /// <summary>
        /// Gets or sets the SurrogateSelector used by the current formatter
        /// </summary>
        ISurrogateSelector IFormatter.SurrogateSelector
        {
            get { return mContext.NativeSurrogateSelector; }
            set { mContext.NativeSurrogateSelector = value;  }
        }

        /// <summary>
        /// Serializes an object, or graph of objects with the given root to the provided stream.
        /// </summary>
        /// <param name="stream">The stream where the formatter puts the serialized data. 
        /// This stream can reference a variety of backing stores (such as files, network, memory, and so on)</param>
        /// <param name="graph">The object, or root of the object graph, to serialize. 
        /// All child objects of this root object are automatically serialized</param>
        public void Serialize(Stream stream, object graph)
        {
            using (NxBinaryWriter writer = new NxBinaryWriter(stream, Encoding.Default, mContext))
            {
                writer.WriteObject(graph);
            }
        }

        /// <summary>
        /// Deserializes the data on the provided stream and reconstitutes the graph of objects.
        /// </summary>
        /// <param name="stream">The stream that contains the data to deserialize</param>
        /// <returns>The top object of the deserialized graph</returns>
        public object Deserialize(Stream stream)
        {
            using (NxBinaryReader reader = new NxBinaryReader(stream, Encoding.Default, mContext))
            {
                return reader.ReadObject();
            }
        }

        #endregion

        #region /       IRemotingFormatter Members       /

        /// <summary>
        /// Serializes an object, or graph of objects with the given root to the provided stream.
        /// </summary>
        /// <param name="stream">The stream where the formatter puts the serialized data. 
        /// This stream can reference a variety of backing stores (such as files, network, memory, and so on)</param>
        /// <param name="graph">The object, or root of the object graph, to serialize. 
        /// All child objects of this root object are automatically serialized</param>
        /// <param name="headers">The array of <see cref="Header"/> objects to transmit with the graph specified by the graph parameter. 
        /// Can be a null reference </param>
        public void Serialize(Stream stream, object graph, Header[] headers)
        {
            using (NxBinaryWriter writer = new NxBinaryWriter(stream, Encoding.Default, mContext))
            {
                writer.WriteObject(graph, headers);
            }
        }

        /// <summary>
        /// Deserializes the data on the provided stream and reconstitutes the graph of objects.
        /// </summary>
        /// <param name="stream">The stream that contains the data to deserialize</param>
        /// <param name="handler">The delegate designed to handle <see cref="Header"/> objects. Can be a null reference</param>
        /// <returns>The top object of the deserialized graph</returns>
        public object Deserialize(Stream stream, HeaderHandler handler)
        {
            using (NxBinaryReader reader = new NxBinaryReader(stream, Encoding.Default, mContext))
            {
                return reader.ReadObject(handler);
            }
        }

        #endregion

        /// <summary>
        /// Resets this instanc of <see cref="NxBinaryFormatter"/> object.
        /// </summary>
        /// <remarks>
        /// Use this method to reset context state if you want to reuse the same <see cref="NxBinaryFormatter"/> instance
        /// for different streams. 
        /// </remarks>
        public void Reset()
        {
            mContext.Clear();
        }

        /// <summary>
        /// Serializes an object, or graph of objects with the given root to the provided stream.
        /// </summary>
        /// <param name="stream">The stream where the formatter puts the serialized data. 
        /// This stream can reference a variety of backing stores (such as files, network, memory, and so on)</param>
        /// <param name="graph">The object, or root of the object graph, to serialize. 
        /// All child objects of this root object are automatically serialized</param>
        /// <param name="type">Serializes the object as an instance of type <paramref name="type"/></param>
        public void SerializeAs(Stream stream, object graph, Type type)
        {
            using (NxBinaryWriter writer = new NxBinaryWriter(stream, Encoding.Default, mContext))
            {
                writer.WriteObjectAs(graph, type);
            }
        }

        /// <summary>
        /// Serializes an object, or graph of objects with the given root to the provided stream.
        /// </summary>
        /// <param name="stream">The stream where the formatter puts the serialized data. 
        /// This stream can reference a variety of backing stores (such as files, network, memory, and so on)</param>
        /// <param name="graph">The object, or root of the object graph, to serialize. 
        /// All child objects of this root object are automatically serialized</param>
        /// <param name="type">Serializes the object as an instance of type <paramref name="type"/></param>
        /// <param name="headers">The array of <see cref="Header"/> objects to transmit with the graph specified by the graph parameter. 
        /// Can be a null reference </param>
        public void SerializeAs(Stream stream, object graph, Type type, Header[] headers)
        {
            using (NxBinaryWriter writer = new NxBinaryWriter(stream, Encoding.Default, mContext))
            {
                writer.WriteObjectAs(graph, type, headers);
            }
        }

        /// <summary>
        /// Deserializes the data on the provided stream and reconstitutes the graph of objects.
        /// </summary>
        /// <param name="stream">The stream that contains the data to deserialize</param>
        /// <param name="type">Deserializes the object as an instance of type <paramref name="type"/></param>
        /// <returns>The top object of the deserialized graph</returns>
        public object DeserializeAs(Stream stream, Type type)
        {
            using (NxBinaryReader reader = new NxBinaryReader(stream, Encoding.Default, mContext))
            {
                return reader.ReadObjectAs(type);
            }
        }

        /// <summary>
        /// Deserializes the data on the provided stream and reconstitutes the graph of objects.
        /// </summary>
        /// <param name="stream">The stream that contains the data to deserialize</param>
        /// <param name="type">Deserializes the object as an instance of type <paramref name="type"/></param>
        /// <param name="handler">The delegate designed to handle <see cref="Header"/> objects. Can be a null reference</param>
        /// <returns>The top object of the deserialized graph</returns>
        public object DeserializeAs(Stream stream, Type type, HeaderHandler handler)
        {
            using (NxBinaryReader reader = new NxBinaryReader(stream, Encoding.Default, mContext))
            {
                return reader.ReadObjectAs(type, handler);
            }
        }

        /// <summary>
        /// Serializes an object, or graph of objects with the given root to the provided stream.
        /// </summary>
        /// <param name="stream">The stream where the formatter puts the serialized data. 
        /// This stream can reference a variety of backing stores (such as files, network, memory, and so on)</param>
        /// <param name="graph">The object, or root of the object graph, to serialize. 
        /// All child objects of this root object are automatically serialized</param>
        /// <param name="context">The context to use for serialization of this root object</param>
        private void Serialize(Stream stream, object graph, NxSerializationContext context)
        {
            using (NxBinaryWriter writer = new NxBinaryWriter(stream, Encoding.Default, context))
            {
                writer.WriteObject(graph);
            }
        }

        /// <summary>
        /// Deserializes the data on the provided stream and reconstitutes the graph of objects.
        /// </summary>
        /// <param name="stream">The stream that contains the data to deserialize</param>
        /// <param name="context">The context to use for deserialization of this root object</param>
        /// <returns>The top object of the deserialized graph</returns>
        private object Deserialize(Stream stream, NxSerializationContext context)
        {
            using (NxBinaryReader reader = new NxBinaryReader(stream, Encoding.Default, context))
            {
                return reader.ReadObject();
            }
        }

        /// <summary>
        /// Serializes an object, or graph of objects with the given root to the provided stream.
        /// </summary>
        /// <param name="graph">The object, or root of the object graph, to serialize. 
        /// All child objects of this root object are automatically serialized</param>
        /// <returns>Serialized byte array</returns>
        public byte[] ToByteArray(object graph)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                Serialize(stream, graph);
                return stream.ToArray();
            }
        }

        /// <summary>
        /// Deserializes the data on the provided stream and reconstitutes the graph of objects.
        /// </summary>
        /// <param name="buffer">binary representation of the object</param>
        /// <returns>The byte array to deserialize</returns>
        public object FromByteArray(byte[] buffer)
        {
            using (MemoryStream stream = new MemoryStream(buffer))
            {
                return Deserialize(stream);
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Architect
Pakistan Pakistan
Let a = b ....... (1)
a - b = a - b
a^2 - ab = a^2 - ab
a^2 - ab = a^2 - b^2 (from 1)
a (a - b) = (a + b) (a - b)
a = (a + b) ...... (2)

if a = 1
1 = (1 + 1) (from 1 & 2)
1 = 2 !!

Comments and Discussions