XML Serialization of Generic Dictionary, Multidimensional Array, and Inherited Type, with sharpSerializer .NET
- Download sharpSerializer Windows DLL - 278.09 KB
- Download sharpSerializer sources and HelloWorld demo - 285.73 KB
- Download latest sources (external link)
Table of Contents
- Introduction
- Background
- Using the Code
- Hello World with
sharpSerializer
- Excluding properties from the serialization
- Customizing the property list for the serialization
- Serialize type name as
AssemblyQualifiedName
instead of the short version "TypeName
,AssemblyName
" - Custom formatting of
DateTime
andfloat
values - Serialize data to other format as XML
- Hello World with
- How does sharpSerializer work?
- Examples of advanced serialization
- Serialize a polymorphic property (where the property value is inherited from the property type)
- Serialize a generic Dictionary where values are inherited from the interface
- Serialize a multidimensional array
- Serialize an array of different object types and an array of array (nested array)
- Serialize other types
- Restrictions of sharpSerializer
- Usage scenarios
- Download current sources
- Author's note
- History
Introduction
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.
Background
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.
Using the Code
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:
// instantiate the object
var obj = new SomeObject(){
SimpleDateTime = new DateTime(2010,4,28),
SimpleEnum = SimpleEnum.Three,
SimpleInt = 42,
SimpleString = "nothing",
SimpleTimeSpan = new TimeSpan(1,2,3)};
// instantiate the sharpSerializer
// with standard constructor it serializes to XML
// overloaded constructors activate binary serialization
var serializer = new SharpSerializer();
// serialize
serializer.Serialize(obj, "test.xml");
// deserialize (to check the serialization)
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 listingAttributesToIgnore
.// remove default ExcludeFromSerializationAttribute for performance gain serializer.PropertyProvider.AttributesToIgnore.Clear(); serializer.PropertyProvider.AttributesToIgnore.Add(typeof(XmlIgnore));
or using the settings class:// for binary mode var settings = new SharpSerializerBinarySettings(); // for xml mode var settings = new SharpSerializerXmlSettings(); // remove default ExcludeFromSerializationAttribute for performance gain 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 propertyCapacity
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 thesharpSerializer
settings.// create the settings var settings = new SharpSerializerBinarySettings(); // for binary mode var settings = new SharpSerializerXmlSettings(); // for xml mode 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();
Serialize Type Name as AssemblyQualifiedName Instead of the Short Version "TypeName, AssemblyName"
All types are serialized by default as "TypeName
, AssemblyName
"; e.g.:
type="System.String, mscorlib"
This is simple, and avoids problems with assembly version during serialization and deserialization.
If you need the full Type.AssemblyQualifiedName
as the type name (i.e. for working with different assembly versions or with signed assemblies), you need to modify the serializer settings and set the properties IncludeAssemblyVersionInTypeName
, IncludeCultureInTypeName
and IncludePublicKeyTokenInTypeName
to true
. This results in the following type name:
type="System.String, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
To achieve this, use the code below:
var settings = new SharpSerializerXmlSettings();
settings.IncludeAssemblyVersionInTypeName = true;
settings.IncludeCultureInTypeName = true;
settings.IncludePublicKeyTokenInTypeName = true;
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.
How Does sharpSerializer Work?
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 andstring
,DateTime
,TimeSpan
and all enumerations.ComplexProperty
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 arrays.MultiDimensionalArrayProperty
for multidimensional arrays.CollectionProperty
for listings which inherit fromICollection
but not fromIDictionary
.DictionaryProperty
for listings which inherit fromIDictionary
.NullProperty
for all objects/strings which arenull
(there is a need to make a notice that they arenull
).
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.
Examples of Advanced Serialization
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
{
/// <summary>
/// Structures are handled as objects during serialization
/// They are serialized as ComplexProperty
/// </summary>
public AdvancedStruct AdvancedStruct { get; set; }
/// <summary>
/// Single dimensional array of simple type.
/// It is serialized as SingleDimensionalArrayProperty
/// </summary>
public string[] SingleArray { get; set; }
/// <summary>
/// Multidimensional array of simple type.
/// Is is serialized as MultiDimensionalArrayProperty
/// </summary>
public string[,] DoubleArray { get; set; }
/// <summary>
/// Single array of derived objects.
/// This is polymorphic collection - Items derive from the interface
/// </summary>
public IComplexObject[] PolymorphicSingleArray { get; set; }
/// <summary>
/// Generic list is serialized as a collection.
/// It is serialized as CollectionProperty
/// </summary>
public IList<string> GenericList { get; set; }
/// <summary>
/// Polymorphic property. Object instance derives from the property type
/// Is serialized as ComplexProperty
/// </summary>
public IComplexObject ComplexObject { get; set; }
/// <summary>
/// Collection where item values are
/// derived from the collection item type
/// </summary>
public ComplexObjectPolymorphicCollection ComplexObjectCollection
{ get; set; }
/// <summary>
/// Dictionary where values are derived
/// from the predefined dictionary value type
/// </summary>
public ComplexObjectPolymorphicDictionary ComplexObjectDictionary
{ get; set; }
/// <summary>
/// List items are derived from the generic attribute.
/// This is polymorphic attribute.
/// </summary>
public IList<IComplexObject> GenericListOfComplexObjects { get; set; }
/// <summary>
/// Generic object with polymorphic attribute.
/// It is serialized as ComplexProperty
/// </summary>
public GenericObject<IComplexObject> GenericObjectOfComplexObject
{ get; set; }
/// <summary>
/// Multidimensional array of generic object with polymorphic attribute
/// </summary>
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?
Restrictions of sharpSerializer
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.)
There are also two limitations according to serialization in .NET Compact Framework and Silverlight:
LowerBound
in an array will always be deserialized as0
regardless of how it was serialized.- It can't serialize
decimal
type.
LowerBound
of an array and decimal
type are not parts of .NET Compact Framework or Silverlight and therefore cannot be handled by the sharpSerializer
.
Usage Scenarios
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).
Download Current Sources
The most recent sources and news are on the project page: www.sharpserializer.com.
Author's Note
If you like sharpSerializer
or this article - please rate it.
History
- 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
Post Comment
O5R0eZ Wow, amazing blog layout! How long have you been blogging for? you made blogging look easy. The overall look of your website is fantastic, as well as the content!
QVWMK5 Your style is really unique in comparison to other people I ave read stuff from. Thank you for posting when you have the opportunity, Guess I will just bookmark this site.
LjBweB Sac Vanessa Bruno Pas Cher Sac Vanessa Bruno Pas Cher
43tkHV Muchos Gracias for your blog article. Great.
EVVODr You made some decent points there. I looked on the net to learn more about the issue and found most individuals will go along with your views on this website.
no65oL There as certainly a lot to learn about this subject. I really like all of the points you have made.
jpojba site link on your page at suitable place and
3gIU04 I truly appreciate this post. I ave been looking all over for this! Thank God I found it on Google. You have made my day! Thank you again
tIsX9x Spot on with this write-up, I seriously believe that this site needs a lot more attention. I all probably be returning to read through more, thanks for the info!
Jbr5wR I used to be suggested this blog via my cousin. I am no longer sure whether this post is written by him as no one else realize such detailed about my trouble. You are wonderful! Thanks!
mWlrCA There exists noticeably a bundle to comprehend this. I suppose you might have made distinct good points in features also.
WmF3ta Its hard to find good help I am forever saying that its difficult to find good help, but here is
lfXnY7 You have noted very interesting details ! ps decent web site. O human race born to fly upward, wherefore at a little wind dost thou fall. by Dante Alighieri.
H9AdXo Well I definitely liked reading it. This article offered by you is very effective for accurate planning.
ssBLgV
f0C8oA Im thankful for the blog post.Thanks Again. Fantastic.
UYNcsB I really liked your blog article.Much thanks again. Want more.
IMzFui I truly appreciate this blog post. Will read on
Rvv1jI Say, you got a nice article.Thanks Again. Really Cool.
2Vz3pN I'll immediately snatch your rss feed as I can't to find your e-mail subscription hyperlink or e-newsletter service. Do you've any? Kindly permit me recognise so that I may just subscribe. Thanks.
X7EAiS Heya i am for the first time here. I came across this board and I to find It really useful & it helped me out much. I'm hoping to present one thing again and help others like you aided me.
T6ajTt My partner and I stumbled over here different web page and thought I should check things out. I like what I see so now i'm following you. Look forward to going over your web page again.
aLMUV0 Say, you got a nice blog post.
TGgv9L Major thankies for the post. Great.
vCQblt Fantastic post.Really thank you! Really Great.
5cBadv Awesome blog article. Cool.
BjOY9V Wow, great blog.Really looking forward to read more. Really Cool.
4PTzmv Say, you got a nice blog post.Thanks Again. Will read on...
jyoswW Fantastic blog article.Really looking forward to read more. Really Great.
2Owk9s Really informative post.Thanks Again. Awesome.
fOUemo Say, you got a nice post.Really looking forward to read more. Fantastic.
mf3M7X Major thankies for the article post. Cool.