Posts Tagged Serialization

SilverlightSerializer Version 2


SilverlightSerializer version 2

Well, I know it’s been a long wait and I’ve been promising the new version of SilverlightSerializer for months, but it’s finally here, extracted from my core project and working standalone.

This new version of the serializer is a major rewrite – with 2 goals in mind:

1. Performance

Serialization performance is 61% faster (my test harness serializes 100,000 objects in 1.03 seconds compared to 1.72)
Deserialization performance is 27% faster (my test hardness deserializes 100,000 objects in 1.61 seconds compared to 2.04)

These performance gains are on large object graphs containing multiple instances of the same types – it would nominally be slightly slower on small graphs or graphs that contain only one copy of each object – but of course that’s very unlikely in the real world.

2. Extensibility

The new version of SilverlightSerializer abstracts the storage methods behind a new interface, IStorage.  There’s a complete implementation of a BinarySerializer that is compatible with the old version of SilverlightSerializer, but you could add your own.  Alterian has built versions that store data in XML and SQL Server tables.  This means one standard semantic serialization layer can be used with pluggable storage types to put the information where you need it for the application at hand.

That said, writing an IStorage is fairly involved process and I’ll write a post or a page on it if people want me to.

In addition the serializer now handles arrays and enums far better than before and hopefully should avoid the dreaded MissingMethod exception by providing a more developer friendly exception and message while offering the opportunity to construct classes without a parameterless constructor using a new CreateType event that will help some avoid the need to write custom serializers.

You can find the version 2 source code here.  In response to a couple of requests, the project is also accessible on GitHub, see the link at the top of the SilverlightSerializer page.

Why is it faster?

So read on if you’d like to know why it’s faster!

SilverlightSerializer is a reflection based serializer.  It examines an object to identify the available properties and fields. As anyone who is familiar with .NET will know, reflection isn’t exactly the fastest thing in the world.  SS v1 did its level best to cache everything possible, but it still relied on reflection to write and read properties and fields from the underlying objects.  This is why SS didn’t perform as well as the inbuilt serializers in .NET.

Now reflection in this case is a hard thing to get around, I don’t know the types in advance and I have no interest in getting the developer to have to write a custom serialization class for each of their types.

The answer to this performance challenge came from using generic classes and using .NET to construct a new generic class on the fly for each property of each class being serialized.  The generic class accesses the native property access functions directly, rather than have to use reflection.  Fields have to be handled slightly differently, with a reflection function, but at least it’s no slower than the previous method.

First let’s start with the base class that is used for all of the generic classes, it’s called GetSet.


public abstract class GetSet
{
public PropertyInfo Info;
public string Name;
public FieldInfo FieldInfo;
public object Vanilla;
public bool CollectionType;
public abstract object Get(object item);
public abstract void Set(object item, object value);

}

From this base class I create a definition of a generic class, called GetSetGeneric.  This class creates Get and Set delegates using the class parameters, these delegates then map to the functions that will be exposed by the property getters and setters on the target class (neat huh).  This happens only once per type/property combination and the resulting code is the same speed as writing a function to get the value.

public class GetSetGeneric<T, TR> : GetSet
{
public delegate TR GetValue(T obj);
public delegate void SetValue(T obj, TR value);
private readonly GetValue _get;
private readonly SetValue _set;

public GetSetGeneric(PropertyInfo info)
{
MethodInfo getMethod;
MethodInfo setMethod = null;
Name = info.Name;
Info = info;
CollectionType = Info.PropertyType.GetInterface("IEnumerable", true) != null;
getMethod = info.GetGetMethod();
setMethod = info.GetSetMethod();
_get = (GetValue)Delegate.CreateDelegate(typeof(GetValue), getMethod);
if (setMethod != null) _set = (SetValue)Delegate.CreateDelegate(typeof(SetValue), setMethod);
}

public GetSetGeneric(FieldInfo info)
{
MethodInfo getMethod;
MethodInfo setMethod = null;
Name = info.Name;
FieldInfo = info;
_get = new GetValue(GetFieldValue);
_set = new SetValue(SetFieldValue);
CollectionType = FieldInfo.FieldType.GetInterface("IEnumerable", true) != null;
return;
}

public GetSetGeneric(string name)
{
Name = name;
MethodInfo getMethod;
MethodInfo setMethod= null;
var t = typeof(T);
var p = t.GetProperty(name);
if (p == null)
{
FieldInfo = typeof(T).GetField(Name);
_get = new GetValue(GetFieldValue);
_set = new SetValue(SetFieldValue);
CollectionType = FieldInfo.FieldType.GetInterface("IEnumerable", true) != null;
return;
}
Info = p;
CollectionType = Info.PropertyType.GetInterface("IEnumerable", true) != null;
getMethod = p.GetGetMethod();
setMethod = p.GetSetMethod();
_get = (GetValue)Delegate.CreateDelegate(typeof(GetValue), getMethod);
if(setMethod != null) _set = (SetValue)Delegate.CreateDelegate(typeof(SetValue), setMethod);
}

private TR GetFieldValue(T obj)
{
return (TR)FieldInfo.GetValue(obj);
}

private void SetFieldValue(T obj, TR value)
{
FieldInfo.SetValue(obj, value);
}

public override object Get(object item)
{
return _get((T)item);
}

public override void Set(object item, object value)
{
_set((T)item, (TR)value);
}
}

Once that’s done it’s just a matter of creating the generic classes. Deserialization does this one property at a time form the input stream:

entryConfiguration = new EntryConfiguration();

var pi = entry.OwningType.GetProperty(entry.Name);
if (pi != null)
{
entryConfiguration.Type = pi.PropertyType;
var gs = typeof(GetSetGeneric<,>);
var tp = gs.MakeGenericType(new Type[] { entry.OwningType, pi.PropertyType });
entryConfiguration.Setter = (GetSet)Activator.CreateInstance(tp, new object[] { pi });
}
else
{
var fi = entry.OwningType.GetField(entry.Name);
if (fi != null)
{
entryConfiguration.Type = fi.FieldType;
var gs = typeof(GetSetGeneric<,>);
var tp = gs.MakeGenericType(new Type[] { entry.OwningType, fi.FieldType });
entryConfiguration.Setter = (GetSet)Activator.CreateInstance(tp, new object[] { fi });
}
}

Here you can see I get either the property or the field information, use the type of the containing class and the property in a call to MakeGenericType to construct the correct class, then create an instance of that class that can be used to get and set properties on the object.
Serialization works by creating a list of getters and setters for every sensible property on the object, in SilverlightSerializer that creates a few different flavours depending on whether you are using Checksums etc. If you want to see how I do that, have a look at the GetWriteableAttributes class and the GetAccessors() function.

, , , , , , , , , ,

10 Comments

Silverlight Binary Serialization


Download

For the latest information, version and more complete documentation, please click here.

Overview

SilverlightSerializer is a binary serializer that works in .NET and Silverlight, allowing you to move your objects between the two instances or store and retrieve them locally in either.  It is highly performant and produces small files which are suitable for further compression if you need to.

It can serialize just about anything, including complex multi-dimensional arrays of complex objects. It can only serialize public fields and properties, unless you write a custom serializer for a particular type.

The serializer can also produce Checksums that can be used to compare different objects to see if they have the same meaning, or to use as file names to see if you have a cached version already available.

There is now a Silverlight Serializer page on this blog where I will keep a version history and add revisions. This page has additional instructions on how to use the serializer and configure your classes, I suggest you take a look at that as I’m going to stop updating this post and start putting information on there.  Feel free to comment in either location however.

Commentary

I finally got fed up with the terrible performance of the DataContract serializer, especially for shared class libraries and was forced to write my own.

The serializer I have created doesn’t need to know about KnownTypes, is capable of suppressing a property or field with a [DoNotSerialize] attribute and writes to a byte array which is much smaller than the bloated XML format favoured by DataContractSerializer. It also handles object references, which you can’t make DCS do in a shared library.

The serialization won’t waste space and therefore doesn’t serialize properties/fields that have their initial values from the constructor. It won’t bother serializing empty collections etc and it uses tokens for type names and property names to save space; though I’m also using SharpZip to compress the output further in a wrapper I’ve put around the serializer in my own code (not shown here, or in the example project). This is sometimes necessary as it does store the AssemblyQualifiedName of the types in the graph (which is the trade off for not marking everything with KnownType in advance). I might look at a way of adding that functionality myself later, but my version doesn’t have problems with conflicting names that DCS frequently pops up.

So you can find the project here if you are interested, feel free to use or modify it in any way you like.

Here’s an example of using it:

        public class outer
        {
            public enum MyModes
            {
                One,
                Two,
                Three
            };
            public string Name { get; set; }
            public Dictionary Dict { get; set; }
            public BaseItem[] Array { get; set; }
            public MyModes Mode { get; set; }
            public outer()
            {
                Name = string.Empty;
                Dict = new Dictionary();
                Array = new BaseItem[10];
            }
        }

Calling the serializer:

             var s = new outer();
            var br = new Branch();  //One of my complex objects
            br.Elements.Add(new FilterBranch());
            s.Dict["Hello"] = br;
            s.Array[2] = new Campaign();
            s.Mode = outer.MyModes.Two;

            var bytes = SilverlightSerializer.Serialize(s);
            var item = SilverlightSerializer.Deserialize(bytes)  as outer;

Update: if you want to share classes between Silverlight and .NET4 make sure you read this post first!

Significant update:

Thanks to Peter and Steve I have modified the serializer so that it handles arrays with more than 2 dimensions and can construct some further types of object.

I’ve also updated it so that you can write your own custom serializers for your types and indeed for system types as well.  The way you do this is by creating a class that implements ISerializeObject and decorate it with a SerializerAttribute which declares the type that the item can serialize (one class is allowed to serialize more than one type, by using the attribute more than once).  The methods of ISerializeObject will then be called for your type – this allows you to have objects without a parameterless constructor be serialized in the normal way.  You must register each assembly that contains these decorated extensions by calling SilverlightSerializer.RegisterSerializationAssembly – if you are calling it from the assembly that contains your extension you don’t need to pass a parameter.

If you want to make your serializer store private properties you can implement the interface on the actual item you want to serialize (still decorating it with the attribute) and therefore have access to them.

Here’s a class without a paramterless constructor and containing a complex array:

public class myClass
{
   public int Parameter;
   public string[,,] Myarray = new string[3,3,3];
   public myClass(int aParameter)
   {
      Parameter = aParameter;
   }
}

Now here’s the definition of a helper class to serialize it:

[Serializer(typeof(myClass))]
public class SerializeMyClass : ISerializeObject
{
   public object[] Serialize(object target)
   {
        return new object[]
           {
               ((myClass) target).Parameter,
               SilverlightSerializer.Serialize(((myClass)target).Myarray)
            };
   }

   public object Deserialize(object[] data)
   {
       var parm = (int) data[0];
       return new myClass(parm)
          {
              Myarray = SilverlightSerializer.Deserialize((byte[]) data[1]) as string[,,]
          };
    }
}

Serializing it might look something like this (though you would probably register your serialization extensions during some init phase):

SilverlightSerializer.RegisterSerializationAssembly();
var cls = new myClass(101);
cls.Myarray[0, 1, 1] = "Hello Mum";
var d = SilverlightSerializer.Serialize(cls);
var x = SilverlightSerializer.Deserialize(d);

 

Further Update

I’ve fixed a number of bugs with serializing Enums when they were stored in an object property and handle Decimals properly.

Silverlight Serializer In Action

Peter Bromberg has come up with a great article on EggheadCafe that combines my serializer with a compression library and some utility classes plus examples. Check it out here.

The serializer has been linked into a persistent storage library for client side isolated storage by Ashiq Alibhai that you can find here.

, , , , , , , , , ,

39 Comments