Table of Contents
sharpSerializer
is an open source object serializer for .NET Framework, .NET Compact Framework and Silverlight. Its purpose is simple - quick object serialization from A to B, without security considerations. In this article, I'll try to convince you that sharpSerializer
can be a lot more than the built-in XMLSerializer and is simpler.
The built-in XmlSerializer
has some restrictions concerning object serialization:
- It cannot serialize multidimensional arrays.
- It cannot serialize a generic
Dictionary<TKey,TValue>
. - It cannot serialize polymorphic properties (with an inherited value type from the property type) out of the box.
- It needs the type of the serialized object in its
Serialize(...)
method. - It needs many attributes to define your business objects, e.g.:
XmlArrayAttribute
, XmlArrayItemAttribute
to define the array of inherited types.
sharpSerializer
overcomes the above restrictions, and serializes objects with no need to mark your objects with additional attributes and without concerning types being serialized.
Hello World with sharpSerializer
Let's assume we have an object:
public class SomeObject
{
public int SimpleInt { get; set; }
public DateTime SimpleDateTime { get; set; }
public TimeSpan SimpleTimeSpan { get; set; }
public SimpleEnum SimpleEnum { get; set; }
public string SimpleString { get; set; }
}
public enum SimpleEnum {One,Two,Three}
We initialize and serialize this object:
var obj = new SomeObject(){
SimpleDateTime = new DateTime(2010,4,28),
SimpleEnum = SimpleEnum.Three,
SimpleInt = 42,
SimpleString = "nothing",
SimpleTimeSpan = new TimeSpan(1,2,3)};
var serializer = new SharpSerializer();
serializer.Serialize(obj, "test.xml");
var obj2 = serializer.Deserialize("test.xml");
Notice! You don't need to mark your object with any attribute, nor do you have to give the object type in the Serialize
method.
This object serializes to the following XML:
<Complex name="Root" type="SharpSerializerTestApp.SomeObject, SharpSerializerTestApp">
<Properties>
<Simple name="SimpleInt" value="42" />
<Simple name="SimpleDateTime" value="04/28/2010 00:00:00" />
<Simple name="SimpleTimeSpan" value="01:02:03" />
<Simple name="SimpleEnum" value="Three" />
<Simple name="SimpleString" value="nothing" />
</Properties>
</Complex>
As you can see, the object type was serialized as "TypeName
, AssemblyName
" and DateTime
was serialized as CultureInfo.InvariantCulture
. Later, I'll show you how to customize the type name (i.e., as AssemblyQualifiedName
) and how to save DateTime
and float
numbers in your desired format.
Excluding Properties from the Serialization
By default, all properties are serialized, which are public
, instance
, and not read-only. All properties which are arrays (Type.IsArray==true
), or which inherit from IEnumerable
, ICollection
or IDictionary
are also serialized. For performance reasons, fields are not serialized.
- To exclude properties in your custom types, you need to mark them with attributes.
ExcludeFromSerializationAttribute
is supported out of the box.
public class MyClass
{
[ExcludeFromSerialization]
public int SimpleInt { get; set; }
}
- If your objects are marked with common .NET Attributes such as
XmlIgnore
, you can add these attributes to the listing AttributesToIgnore
.
serializer.PropertyProvider.AttributesToIgnore.Clear();
serializer.PropertyProvider.AttributesToIgnore.Add(typeof(XmlIgnore));
or using the settings
class:
var settings = new SharpSerializerBinarySettings();
var settings = new SharpSerializerXmlSettings();
settings.AdvancedSettings.AttributesToIgnore.Clear();
settings.AdvancedSettings.AttributesToIgnore.Add(typeof(XmlIgnore));
- To exclude properties of the built in .NET types, or if you cannot extend properties with attributes, you add the type and its property name to the list
SharpSerializer.PropertyProvider.PropertiesToIgnore
.
i.e. System.Collections.Generic.List<T>
has property Capacity
which is irrelevant for the serialization, thus it should be ignored.
serializer.PropertyProvider.PropertiesToIgnore.Add
(typeof(List<string>), "Capacity");
PropertiesToIgnore
can be also accessed from the sharpSerializer
settings.
var settings = new SharpSerializerBinarySettings();
var settings = new SharpSerializerXmlSettings();
settings.AdvancedSettings.PropertiesToIgnore.Add(typeof(List), "Capacity");
Customizing the Property List for Serialization
If it is not enough to filter properties with ExcludeFromSerializationAttribute
, AttributesToIgnore
or PropertiesToIgnore
, you can build your CustomPropertyProvider
. As a base class, there is PropertyProvider
, which has two virtual methods GetAllProperties()
and IgnoreProperty(...)
. They can be overwritten to customize the logic.
serializer.PropertyProvider = new MyCustomPropertyProvider();
Serializing type as AssemblyQualifiedName or as a short type name "TypeName, AssemblyName"
Before SharpSerializer v.2.12, all types were serialized as short type name "TypeName
, AssemblyName
"; i.e.:
type="System.String, mscorlib"
This was simple to read, output size was small. But it encountered problems during deserialization if working with signed assemblies or their specific versions.
Since SharpSerializer v.2.12 are all types serialized as AssemblyQualifiedName
; i.e.:
type="System.String, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
You can alter the type naming by altering settings of sharpSerializer and setting the properties IncludeAssemblyVersionInTypeName
, IncludeCultureInTypeName
and IncludePublicKeyTokenInTypeName
. As default, these properties are set to true
.
var settings = new SharpSerializerXmlSettings();
settings.IncludeAssemblyVersionInTypeName = false;
settings.IncludeCultureInTypeName = false;
settings.IncludePublicKeyTokenInTypeName = false;
var serializer = new SharpSerializer(settings);
Custom Formatting of DateTime and Float Values
By default, all primitive types and DateTime
are converted to string
s according to CultureInfo.InvariantCulture
. If custom formatting or a culture is needed, this can be achieved with the following modification of the settings class:
var settings = new SharpSerializerXmlSettings();
settings.Culture = System.Globalization.CultureInfo.CurrentCulture;
var serializer = new SharpSerializer(settings);
Serialize Data to Other Format as XML
Actually, sharpSerializer
can serialize to XML and to its own binary format. However, after injecting it with custom IXmlWriter
or IBinaryWriter
it can serialize data to other text formats like Json or other encrypted, compressed, optimized, etc. binary streams. Please refer to the project site for details concerning binary serialization.
It works in three steps:
Step 1
The PropertyFactory
converts an object to the Property
. The abstract
class Property
contains PropertyCollection
. PropertyCollection
represents the object structure and its data. The following classes inherit from the Property
class:
SimpleProperty
for describing all primitive types and string
, DateTime
, TimeSpan
and all enumerationsComplexProperty
for other classes and structures which are not listings ComplexReferenceProperty
for referencing a class which was already serialized (it saves space.) SingleDimensionalArrayProperty
for single dimensional arraysMultiDimensionalArrayProperty
for multidimensional arraysCollectionProperty
for listings which inherit from ICollection
but not from IDictionary
DictionaryProperty
for listings which inherit from IDictionary
NullProperty
for all objects/strings which are null
(there is a need to make a notice that they are null
)
Step 2
Property
is serialized by XmlPropertySerializer
. In which format it is serialized depends on the used writer.
Step 3
For XML serialization, DefaultXmlWriter is responsible
. But as a sink can be used any writer, which implements IXmlWriter
. In this way, you can write your own writers which serialize data to other formats like Json.
During deserialization, the process is inversed. An instance of IXmlReader
reads the data and forwards it to the XmlPropertyDeserializer
, which deserializes the data into Property
. Finally, ObjectFactory
converts Property
into object.
Please download the source code for more details.
Following examples are parts of the HelloWorldDemo
application which you can download with the source code.
Serialize a Polymorphic Property (where Property Value is Inherited from the Property Type)
There is a property of type IComplexObject
. The property value contains a class ComplexObject
which is inherited from IComplexObject
.
public IComplexObject ComplexObject { get; set; }
There is no need to input the type being serialized. sharpSerializer
can serialize the expected type and any inherited type out of the box:
<Complex name="ComplexObject"
type="HalloWorldApp.BusinessObjects.ComplexObject, HalloWorldApp">
<Properties>
<Simple name="SimpleInt" value="33" />
</Properties>
</Complex>
Serialize a Generic Dictionary where Values are Inherited from the Interface
There is a generic dictionary where values are of some complex class which is inherited from the interface IComplexObject
(polymorphic argument):
public IDictionary<int, IComplexObject> GenericDictionary { get; set; }
It serializes to:
<Dictionary name="GenericDictionaryOfPolymorphicValues"
type="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],
[HalloWorldApp.BusinessObjects.IComplexObject, HalloWorldApp]],
mscorlib" keyType="System.Int32, mscorlib"
valueType="HalloWorldApp.BusinessObjects.IComplexObject, HalloWorldApp">
<Items>
<Item>
<Simple value="2012" />
<Complex type="HalloWorldApp.BusinessObjects.ComplexObject, HalloWorldApp">
<Properties>
<Simple name="SimpleInt" value="2012000" />
</Properties>
</Complex>
</Item>
</Items>
</Dictionary>
As you can see, the type of keys and values does not matter. sharpSerializer
can serialize primitive types, complex objects, and even nested listings, e.g., dictionaries.
Serialize a Multidimensional Array
There is a two dimensional array (it could have more dimensions):
public string[,] DoubleArray { get; set; }
It serializes to:
<MultiArray name="DoubleArray" elementType="System.String, mscorlib">
<Dimensions>
<Dimension length="3" />
<Dimension length="2" />
</Dimensions>
<Items>
<Item indexes="0,0">
<Simple value="k1" />
</Item>
<Item indexes="0,1">
<Simple value="k2" />
</Item>
<Item indexes="1,0">
<Simple value="b1" />
</Item>
<Item indexes="1,1">
<Simple value="b2" />
</Item>
<Item indexes="2,0">
<Simple value="z1" />
</Item>
<Item indexes="2,1">
<Simple value="z2" />
</Item>
</Items>
</MultiArray>
It does not matter of what type the array is. sharpSerializer
can serialize an array of any object, array of arrays, array of collections, or an array of dictionaries. It can serialize really deep nested arrays.
Serialize an Array of Different Object Types and Array of Arrays (Nested Array)
There is an array of the following objects:
root.SingleArrayOfObjects = new object[]
{
42,
"nothing to say",
false,
BusinessObjects.SimpleEnum.Three,
null,
new object[]
{
42,
"nothing to say",
false,
BusinessObjects.SimpleEnum.Three,
null
}
};
It serializes to:
<SingleArray name="SingleArrayOfObjects" elementType="System.Object, mscorlib">
<Items>
<Simple type="System.Int32, mscorlib" value="42" />
<Simple type="System.String, mscorlib" value="nothing to say" />
<Simple type="System.Boolean, mscorlib" value="False" />
<Simple type="HalloWorldApp.BusinessObjects.SimpleEnum,
HalloWorldApp" value="Three" />
<Null />
<SingleArray type="System.Object[], mscorlib"
elementType="System.Object, mscorlib">
<Items>
<Simple type="System.Int32, mscorlib" value="42" />
<Simple type="System.String, mscorlib" value="nothing to say" />
<Simple type="System.Boolean, mscorlib" value="False" />
<Simple type="HalloWorldApp.BusinessObjects.SimpleEnum, HalloWorldApp"
value="Three" />
<Null />
</Items>
</SingleArray>
</Items>
</SingleArray>
Serialize Other Types
Please download the source code to see the whole example and what else can be serialized. Below are some other properties from the HelloWorldDemo
:
public class RootContainer
{
public AdvancedStruct AdvancedStruct { get; set; }
public string[] SingleArray { get; set; }
public string[,] DoubleArray { get; set; }
public IComplexObject[] PolymorphicSingleArray { get; set; }
public IList<string> GenericList { get; set; }
public IComplexObject ComplexObject { get; set; }
public ComplexObjectPolymorphicCollection ComplexObjectCollection
{ get; set; }
public ComplexObjectPolymorphicDictionary ComplexObjectDictionary
{ get; set; }
public IList<IComplexObject> GenericListOfComplexObjects { get; set; }
public GenericObject<IComplexObject> GenericObjectOfComplexObject
{ get; set; }
public GenericObject<IComplexObject>[,]
MultiArrayOfGenericObjectWithPolymorphicArgument
{ get; set; }
}
public interface IComplexObject { int SimpleInt { get; set; } }
public class ComplexObject : IComplexObject {public int SimpleInt
{ get; set; }}
public class ComplexObjectPolymorphicCollection :
Collection<IComplexObject>{}
public class ComplexObjectCollection :
Collection<ComplexObject>{}
public class ComplexObjectPolymorphicDictionary :
Dictionary<int, IComplexObject>{}
public class ComplexObjectDictionary :
Dictionary<int, ComplexObject>{}
What do you think? Is XML serialization with sharpSerializer
simple enough?
In the current version of sharpSerializer
, there are some restrictions concerning serialization and deserialization of objects. In the future, these restrictions can be neutralized, but actually they make no such pain. These are:
- Objects without their
public
standard constructor cannot be deserialized. Multiple references to the same complex object are not optimized. Such multiple referenced object is serialized as many times as many references to it. (SharpSerializer
v.2.9 and above can optimize serializing of multiple references to the same object. Such an object is serialized only once. This optimization results with smaller file size.)
Following limitation concerns serialization in .NET Compact Framework and Silverlight:
LowerBound
in an array will always be deserialized as 0
regardless of how it was serialized.
LowerBound
of an array is not a part of .NET Compact Framework or Silverlight and therefore cannot be handled by the sharpSerializer
.
The main reason why I developed sharpSerializer
was to save application configuration in an XML file. Few years ago, I was struggling with a polymorphic configuration. I needed a lightweight configuration storage with support for object inheritance. The file should be easily readable and manually editable. The System.Configuration
has a big overhead and is too stiff.
The second reason is simple - Silverlight has poor support for the local data repository - it should have a better one :-).
Especially interesting is its possibility to serialize data to the binary format in WP7 (Windows Phone 7).
The most recent sources and news are on the project page: www.sharpserializer.com.
If you like sharpSerializer
or this article - please rate it. If not, please make a comment below ;-)
- 2011-11-09: Changes according to
sharpSerializer
v.2.16 - 2011-10-24: Updated download files
- 2011-07-31: Updated download files
SharpSerializer
v.2.12 - 2011-07-28: Updated download files
sharpSerializer
v.2.11 - 2011-05-08: Changes according to
sharpSerializer
v.2.9, Guid
serialization, AttributesToIgnore
and optimized serialization of multiple references to the same object - 2010-10-07: Updated download files
- 2010-10-03: Changes according to
sharpSerializer
v.2.0 - 2010-05-05: Changes according to
sharpSerializer
v.1.2 - 2010-05-04: Added support for the .NET Compact Framework
- 2010-04-30: Formatting changes (cut off some parts of the big XML example)
- 2010-04-29: First release