Mark Wilson I am the creator of TopXML. I am available for international and local (Australia) contracts. I am a Solution Architect/Business Analyst. I have worked in IT in several countries (NZ, Australia, South Africa, UK) building and training teams for government and very large non-governmental organizations. I am ex-Microsoft Consulting Services. I wrote the first book on Microsoft XML published in 2000 called XML Programming with VB and ASP. Most recently I have been building tools for the SEO industry. Ask me for a 37 point SEO health-checkup for your website.
In the previous example, the metadata attributes overrode the
XmlSerializer’s default formatting, but serialization worked
just fine before we attached any attributes. In some cases, however, attributes
are required for the XmlSerializer to produce any output. The next three
sections will show us why.
Before we go on learning about applying attributes, let’s take a
moment to understand what’s going on inside the
XmlSerializer. All the XmlSerializer constructors expect to
receive some information about the types of objects they are going to serialize
over their lifetime. Most overloads require passing in a type object directly.
One of them expects the type information in a pre-processed format, the
XmlTypeMapping, but we ignore that one because it is intended to support
ASP.NET WebServices, and is not for public consumption.
1.1
Table 9.3 The
different overloads of the XmlSerializer constructor require specifying types
the serializer instance will process and offers several options to customize
the default class-to-XML-type mappings.
Constructor
Description
public
XmlSerializer(
Type type
);
Constructs an
XmlSerializer that can process objects of type type
public
XmlSerializer(
XmlTypeMapping xmlTypeMapping
);
Constructs an
XmlSerializer that can process objects described by the xmlTypeMapping.
public
XmlSerializer(
Type type,
string defaultNamespace
);
Constructs an
XmlSerializer that can process objects of type type and defines the default XML namespace for all processed
types.
public
XmlSerializer(
Type type,
Type[] extraTypes
);
Constructs an
XmlSerializer that can process objects of type type and the types in extraTypes.
public
XmlSerializer(
Type type,
XmlAttributeOverrides overrides
);
Constructs an
XmlSerializer that can process objects of type type and applies the XML serialization attributes to customize
the class to XML type mappings.
public XmlSerializer(
Type type,
XmlRootAttribute root
);
Constructs an
XmlSerializer that can process objects of type type and specifies the properties of the root nodes of the
serialized objects.
public
XmlSerializer(
Type type,
XmlAttributeOverrides overrides,
Type[] extraTypes,
XmlRootAttribute root,
string defaultNamespace
);
Constructs an
XmlSerializer that can process objects of type type and the types in extraTypes,
applies the XML serialization attributes to customize the class to XML type
mappings, specifies the properties of the root nodes of the serialized
objects and defines the default XML namespace for all processed types.
Parameters except type can be null.
The constructors use the reflection features of the .NET
framework to analyze a type’s public fields and properties and then store the
type’s structure, i.e. fields field types and metadata attributes, in a type
mapping. By default the
XmlSerializer maps each field or property to an XML element
with the same name, unless it finds an attribute attached to the field to
change the element’s name or map the field to an XML attribute. In those cases
it modifies the type mapping according to the information found in the
attribute.
NOTE: It is good practice to always provide XML serialization
attributes to explicitly declare corresponding element and attribute names,
instead of relying on the default mapping. Without explicit mapping directives
modifications to the source code might affect the serialization format, but if
we declare the serialization format explicitly we can protect ourselves from
problems caused by inadvertent source code changes.
These mappings are then processed into on-the-fly generated
classes which are compiled into a temporary assembly to make serialization and
deserialization very fast. Extracting the type information and processing it
and compiling the temporary assembly, on the other hand, is a very computing
intensive operation. When we design applications with the
XmlSerializer, we should try to instantiate it only once and
keep it around for the lifetime of an application to minimize the performance
hit when we instantiate the serializer and maximize the performance gain of the
cached type information.
During serialization the serializer will query each
object for its type, check the cache for a corresponding type mapping and
persist the object in the format defined by the mapping. Serialize() throws an exception if it cannot locate a mapping
for the exact type.
On a class: Each class can declare substitute types for
the type the attribute is attached to. Substitutes are
typically derived classes which can occur at run-time instead of the base
class.
On a member: We can specify the types that might by
assigned to a field at runtime and even customize the XML mappings dependent on
the type. We can take advantage of these type declarations if we can either not
provide information about substitute types at the class or if we want
finer-grained control over the XML format.