Click here to Skip to main content
15,867,327 members
Articles / Programming Languages / C#
Article

AltSerializer - An Alternate Binary Serializer

Rate me:
Please Sign up or sign in to vote.
4.93/5 (27 votes)
19 Sep 20066 min read 140.8K   1.9K   69   41
The AltSerializer is a replacement for the binary serializer built in to .NET.

Introduction

The AltSerializer is a replacement for the binary serializer built in to .NET. I built it to be quick and easy to use, and hopefully, it works exactly like one would expect it to. I've started using it quite a bit now, and I hope that others find it useful, too.

Features

  • Faster, and much smaller than the default binary formatter.
  • Optionally serializes property/field names along with the data, easing versioning and development.
  • Supports nullable types.
  • Caches serialized objects so they are never serialized twice; circular references are serialized correctly.
  • IAltSerializable interface for custom serialization implementations.
  • If an object implements ISerializable, the serializer will use that interface.
  • With the CompiledSerializer attribute, the serializer can dynamically compile methods to serialize/deserialize your class.
  • Works with Mono.

Description

The AltSerializer will decompose any object it is given, and serialize all (including protected/private) properties/fields in the object. By default, the serializer uses only the properties of an object; but by setting a flag, it will enumerate the fields instead. I tend to stick with properties, because they are most often the editable portion of objects that I use with other components (for example, PropertyGrid). Any read-only or write-only properties are ignored, as well as any fields marked as NonSerialized. The only limitation on the object is that the object must have a parameter-less default constructor.

The AltSerializer also knows about most system types, and can effectively encode them without storing much metadata. Most of these types are also not cached (integers, shorts, booleans, bytes, etc.) because they are too small to effectively cache. Any type that the serializer does not know about is stored by their assembly qualified names - this means whoever is doing the deserialization must also know about the types encoded in the stream. The types are only stored once; then they are cached away to avoid unnecessary bloat.

I ran some benchmarks against the binary formatter, for reference. To be fair, the binary formatter is not very good at serializing small objects. There are some cases where the binary formatter outperforms AltSerializer; obviously, I'm working on fixing that. Each test measures the time it took to perform 100,000 serializations/deserializations of the type in the Test column. The size difference is the difference between the binary formatter output and the AltSerializer output. The time difference is the difference between the binary serializer time and the AltSerializer time.

Image 1

Getting Started

Using the Serializer

The library comes with some static methods for serialization that you can get started with right away:

C#
byte [] bytes = Serializer.Serialize("Hello, World!");
object myObject = Serializer.Deserialize(bytes);

These two methods work for just about anything you want to throw at the serializer, and are probably all you will need to use. To specify properties that the serializer should ignore, tag them with a DoNotSerialize attribute.

The AltSerializer creates metadata information about objects it encounters as it encounters them, so there will probably be a slight delay (whatever delay that is associated with reflecting the object) the first time you attempt to serialize or deserialize with it.

AltSerializer Settings

You can change the settings of the serializer by changing the value of the Serializer.DefaultSerializeFlags variable. (If you instantiate your own serializer, it has its own properties for settings.) The following settings are available in any combination:

  • SerializePropertyNames - Encodes properties/fields that were serialized along with the data. (More on this below.)
  • SerialzationCache - Enables the serialization class. There's little reason not to have this one on.
  • SerializeProperties - Serializes the properties of an object instead of the fields.

When the SerializePropertyNames flag is set, the serializer records the fields or properties it serialized along with the data. When the object is deserialized, if any of the properties/fields are missing, then they are discarded. Likewise, any fields that are new are ignored. This works great for maintaining backwards compatibility without much effort. I use this all the time during development, especially when my objects are still evolving and I'm adding new properties all the time.

One other important setting is the Serializer.DefaultEncoding property, which is used when serializing strings. For example, if you don't need strings as Unicode, you could change this setting to Encoding.ASCII.

Advanced Features

Specifying Type Information

By default, the library encodes type information about an object before it serializes it, so that it knows how to deserialize the object without any prior knowledge. However, it can be useful to cut down on the size of the serialized object by specifying the type of object you're serializing. Obviously, you will have to specify the type again as you're deserializing:

C#
byte[] bytes = Serializer.Serialize(myObject, typeof(MyObjectType));
object newObject = Serializer.Deserialize(bytes, typeof(MyObjectType));

This won't make much of a difference on system types, but it will prevent the serializer from writing out the type name (which it will) for types that it doesn't know about.

Manipulating the Cache

Objects can also be permanently added to the cache. When the serializer encounters these objects, it only writes a reference to it, and the object itself is never serialized. This assumes, of course, that the deserializer used to deserialize the objects is initialized with cache objects in the same order that the serializer was! This isn't an issue if you use the same instance of the AltSerializer class, or if you use the static methods; but it may be an issue if you have two different processes that utilize the AltSerializer. This is especially useful for letting the serializer know about all the types you may want to serialize. The full type information is never stored in the serialized stream, and the data becomes almost purely raw data.

C#
Serializer.CacheObject(typeof(MyObjectType));
byte[] bytes = Serializer.Serialize(obj);
object myObject = Serializer.Deserialize(bytes);

IAltSerializable Interface

If your object implements IAltSerializable, you can specify a custom serialization and deserialization routine. This gives your object access to most of the Write and Read methods in the serializer, which you can use to efficiently serialize the properties you need. Make sure your object always serializes and deserializes properly, because the serializer will probably throw an exception if you don't read back all of the data that you wrote.

C#
public class MyClass : IAltSerializable
{
    private int _value;
    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }

    #region IAltSerializable Members

    public void Serialize(AltSerializer serializer)
    {
        serializer.Write(Value);
    }

    public void Deserialize(AltSerializer deserializer)
    {
        Value = deserializer.ReadInt32();
    }

    #endregion
}

Dynamically Compiled Serializers

Finally, there is a CompiledSerializer attribute you can place in front of your class. If the serializer sees this, it will dynamically emit code to serialize and deserialize your object. Using a compiled serializer/deserializer is quite a bit faster than doing it via reflection; however, there are some limitations. Only compiled properties are able to be serialized (for now). There are still a few optimizations that could be made, I just haven't afforded the time to make them - so far the speed of the serializer has not been an issue.

Testing

I built a project based on NUnit to unit test as many cases that I could think of. It's not the neatest code by any means, but I think it gets the job done. Of course, if you find any cases that break the serializer, please let me know!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I've been writing code since I started learning BASIC on the Apple //c. Since then, I've learned C, C++, a few assembly languages. I went to college for Computer Science and Mathematics at the University of Texas at Dallas.

Comments and Discussions

 
BugSerializePropertyNames is broken Pin
Dwedit_26-Apr-13 12:25
Dwedit_26-Apr-13 12:25 
GeneralProblem on deserialization - JSON Pin
h_e_z_i9-Mar-11 0:18
h_e_z_i9-Mar-11 0:18 
GeneralBug fix for using SerializePropertyNames Pin
rotem28-Jun-10 5:13
rotem28-Jun-10 5:13 
QuestionDatasets ? Pin
gotpewi24-Nov-09 3:26
gotpewi24-Nov-09 3:26 
GeneralExample of breaking alt serializer [modified] Pin
puromtec122-Oct-09 10:05
puromtec122-Oct-09 10:05 
GeneralRe: Example of breaking alt serializer Pin
puromtec122-Oct-09 10:30
puromtec122-Oct-09 10:30 
GeneralRe: Example of breaking alt serializer [solved] Pin
puromtec123-Oct-09 4:03
puromtec123-Oct-09 4:03 
GeneralRe: Example of breaking alt serializer [solved] Pin
Mikael Svenson7-Nov-09 9:48
Mikael Svenson7-Nov-09 9:48 
GeneralSystem.StackOverflowException when serializing Pin
Carol Zambon5-Nov-08 2:30
Carol Zambon5-Nov-08 2:30 
QuestionAltSerializer much slower than built-in seriazliser? Pin
wagger21-May-08 0:32
wagger21-May-08 0:32 
AnswerRe: AltSerializer much slower than built-in seriazliser? Pin
wagger27-Aug-08 1:31
wagger27-Aug-08 1:31 
GeneralRe: AltSerializer much slower than built-in seriazliser? Pin
carga5-Sep-12 20:49
carga5-Sep-12 20:49 
QuestionClasses without default constructor Pin
martinpokus15-May-08 2:24
martinpokus15-May-08 2:24 
AnswerRe: Classes without default constructor Pin
neocognitron15-May-08 12:30
neocognitron15-May-08 12:30 
GeneralProblem with Deserialize - SerializeFlags wrong? [modified] Pin
wagger7-May-08 6:15
wagger7-May-08 6:15 
GeneralRe: Problem with Deserialize - SerializeFlags wrong? Pin
wagger7-May-08 9:53
wagger7-May-08 9:53 
GeneralRe: Problem with Deserialize - SerializeFlags wrong? Pin
neocognitron9-May-08 14:07
neocognitron9-May-08 14:07 
Generalfields Pin
gorilladaddy18-Mar-08 8:51
gorilladaddy18-Mar-08 8:51 
Excellent! Have you implemented a GenerateSerializeMethod which does fields yet?
GeneralRe: fields Pin
neocognitron9-May-08 14:08
neocognitron9-May-08 14:08 
GeneralRe: fields Pin
gorilladaddy10-May-08 4:41
gorilladaddy10-May-08 4:41 
Generalproblem [modified] Pin
tobi_z12-Oct-07 11:53
tobi_z12-Oct-07 11:53 
GeneralException Parameter Count Mismatch Pin
ScruffyDuck27-Jun-07 5:35
ScruffyDuck27-Jun-07 5:35 
GeneralList<Object> - Object within objects - Serialization speed Pin
Benoittr24-Apr-07 10:40
Benoittr24-Apr-07 10:40 
GeneralRe: List<Object> - Object within objects - Serialization speed Pin
Benoittr26-Apr-07 4:27
Benoittr26-Apr-07 4:27 
GeneralRe: List<Object> - Object within objects - Serialization speed Pin
neocognitron27-Apr-07 5:37
neocognitron27-Apr-07 5:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.