XML Serialization and Deserialization in C

This article provides a practical guide on converting C# objects to XML data and back using the built-in XmlSerializer class from the System.Xml.Serialization namespace. You will learn the core requirements for serializable classes, step-by-step implementations for both serialization and deserialization, and the most common XML attributes used to customize the output structure.

Requirements for Serializable Classes

To work with XmlSerializer, your target class must satisfy two fundamental requirements:

  1. It must have a public, parameterless constructor.
  2. Only public properties and public fields can be serialized.
using System.Xml.Serialization;

[XmlRoot("Product")]
public class Product
{
    [XmlAttribute("id")]
    public int Id { get; set; }

    [XmlElement("ProductName")]
    public string Name { get; set; }

    [XmlElement("UnitPrice")]
    public decimal Price { get; set; }

    [XmlIgnore]
    public string InternalCode { get; set; }

    // Required parameterless constructor
    public Product() { }

    public Product(int id, string name, decimal price)
    {
        Id = id;
        Name = name;
        Price = price;
    }
}

How to Serialize an Object to XML

Serialization transforms an in-memory object instance into an XML document or string. You instantiate an XmlSerializer by passing the object's type, create a stream or writer, and invoke the Serialize method.

Serializing to a String

using System;
using System.IO;
using System.Xml.Serialization;

public class SerializationDemo
{
    public static string SerializeToXmlString<T>(T objectToSerialize)
    {
        var serializer = new XmlSerializer(typeof(T));
        using var stringWriter = new StringWriter();
        serializer.Serialize(stringWriter, objectToSerialize);
        return stringWriter.ToString();
    }
}

Serializing Directly to a File

public static void SerializeToFile<T>(T objectToSerialize, string filePath)
{
    var serializer = new XmlSerializer(typeof(T));
    using var fileStream = new FileStream(filePath, FileMode.Create);
    serializer.Serialize(fileStream, objectToSerialize);
}

How to Deserialize XML to an Object

Deserialization reads XML content and reconstructs it into a strongly typed C# object. Use the Deserialize method of XmlSerializer and cast the result to your target type.

Deserializing from a String

using System.IO;
using System.Xml.Serialization;

public class DeserializationDemo
{
    public static T DeserializeFromXmlString<T>(string xmlContent)
    {
        var serializer = new XmlSerializer(typeof(T));
        using var stringReader = new StringReader(xmlContent);
        return (T)serializer.Deserialize(stringReader);
    }
}

Deserializing Directly from a File

public static T DeserializeFromFile<T>(string filePath)
{
    var serializer = new XmlSerializer(typeof(T));
    using var fileStream = new FileStream(filePath, FileMode.Open);
    return (T)serializer.Deserialize(fileStream);
}

Common XML Attributes for Customization

By default, XmlSerializer maps property names directly to XML element tags. You can modify this behavior using attributes:

  • [XmlRoot("TagName")]: Sets the name of the root element when serializing the class.
  • [XmlElement("TagName")]: Specifies that a property should be represented as a nested XML element with a custom name.
  • [XmlAttribute("AttributeName")]: Serializes the property as an attribute on the enclosing element instead of a child node.
  • [XmlIgnore]: Excludes the property completely from serialization and deserialization.
  • [XmlArray("CollectionName")] and [XmlArrayItem("ItemName")]: Formats how lists and arrays are represented in the XML structure.

Handling Common Issues

  • Type Mismatch: If XML elements cannot be converted into their target C# types (e.g., non-numeric text in an integer node), an InvalidOperationException with an inner FormatException is thrown.
  • Namespaces: Unwanted default XML namespaces (like xmlns:xsi and xmlns:xsd) can be omitted during serialization by passing an empty XmlSerializerNamespaces instance to the Serialize method.
  • Performance: Creating dynamic instances of XmlSerializer for non-root types can cause memory leaks. Always cache your serializer instances or use standard typeof() constructors, which are internally cached by .NET.