.NET Framework
XmlSerializer
Zoeken…
Opmerkingen
Gebruik de XmlSerializer
niet om HTML
te parseren. Hiervoor zijn speciale bibliotheken beschikbaar, zoals het HTML Agility Pack
Serialiseer object
public void SerializeFoo(string fileName, Foo foo)
{
var serializer = new XmlSerializer(typeof(Foo));
using (var stream = File.Open(fileName, FileMode.Create))
{
serializer.Serialize(stream, foo);
}
}
Object deserialiseren
public Foo DeserializeFoo(string fileName)
{
var serializer = new XmlSerializer(typeof(Foo));
using (var stream = File.OpenRead(fileName))
{
return (Foo)serializer.Deserialize(stream);
}
}
Gedrag: wijs elementnaam toe aan eigenschap
<Foo>
<Dog/>
</Foo>
public class Foo
{
// Using XmlElement
[XmlElement(Name="Dog")]
public Animal Cat { get; set; }
}
Gedrag: Naam van array van kaart naar eigenschap (XmlArray)
<Store>
<Articles>
<Product/>
<Product/>
</Articles>
</Store>
public class Store
{
[XmlArray("Articles")]
public List<Product> Products {get; set; }
}
Opmaak: Aangepaste datum / tijd-indeling
public class Dog
{
private const string _birthStringFormat = "yyyy-MM-dd";
[XmlIgnore]
public DateTime Birth {get; set;}
[XmlElement(ElementName="Birth")]
public string BirthString
{
get { return Birth.ToString(_birthStringFormat); }
set { Birth = DateTime.ParseExact(value, _birthStringFormat, CultureInfo.InvariantCulture); }
}
}
Efficiënt bouwen van meerdere serializers met dynamisch gespecificeerde afgeleide types
Waar we vandaan kwamen
Soms kunnen we niet alle vereiste metagegevens leveren die nodig zijn voor het XmlSerializer-framework in kenmerk. Stel dat we een basisklasse van geserialiseerde objecten hebben en dat sommige afgeleide klassen onbekend zijn voor de basisklasse. We kunnen geen kenmerk plaatsen voor alle klassen die niet bekend zijn tijdens het ontwerp van het basistype. We zouden een ander team kunnen hebben dat enkele van de afgeleide klassen ontwikkelt.
Wat kunnen we doen
We kunnen new XmlSerializer(type, knownTypes)
, maar dat zou een O (N ^ 2) -bewerking zijn voor N-serialiseerders, tenminste om alle typen argumenten te ontdekken die in argumenten worden geleverd:
// Beware of the N^2 in terms of the number of types.
var allSerializers = allTypes.Select(t => new XmlSerializer(t, allTypes));
var serializerDictionary = Enumerable.Range(0, allTypes.Length)
.ToDictionary (i => allTypes[i], i => allSerializers[i])
In dit voorbeeld is het basistype niet op de hoogte van de afgeleide typen, wat normaal is in OOP.
Doet het efficiënt
Gelukkig is er een methode die dit specifieke probleem aanpakt - bekende typen voor meerdere serializers efficiënt leveren:
System.Xml.Serialization.XmlSerializer.FromTypes Method (Type [])
Met de methode FromTypes kunt u efficiënt een array van XmlSerializer-objecten maken voor het verwerken van een array van Type-objecten.
var allSerializers = XmlSerializer.FromTypes(allTypes);
var serializerDictionary = Enumerable.Range(0, allTypes.Length)
.ToDictionary(i => allTypes[i], i => allSerializers[i]);
Hier is een compleet codevoorbeeld:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Linq;
using System.Linq;
public class Program
{
public class Container
{
public Base Base { get; set; }
}
public class Base
{
public int JustSomePropInBase { get; set; }
}
public class Derived : Base
{
public int JustSomePropInDerived { get; set; }
}
public void Main()
{
var sampleObject = new Container { Base = new Derived() };
var allTypes = new[] { typeof(Container), typeof(Base), typeof(Derived) };
Console.WriteLine("Trying to serialize without a derived class metadata:");
SetupSerializers(allTypes.Except(new[] { typeof(Derived) }).ToArray());
try
{
Serialize(sampleObject);
}
catch (InvalidOperationException e)
{
Console.WriteLine();
Console.WriteLine("This error was anticipated,");
Console.WriteLine("we have not supplied a derived class.");
Console.WriteLine(e);
}
Console.WriteLine("Now trying to serialize with all of the type information:");
SetupSerializers(allTypes);
Serialize(sampleObject);
Console.WriteLine();
Console.WriteLine("Slides down well this time!");
}
static void Serialize<T>(T o)
{
serializerDictionary[typeof(T)].Serialize(Console.Out, o);
}
private static Dictionary<Type, XmlSerializer> serializerDictionary;
static void SetupSerializers(Type[] allTypes)
{
var allSerializers = XmlSerializer.FromTypes(allTypes);
serializerDictionary = Enumerable.Range(0, allTypes.Length)
.ToDictionary(i => allTypes[i], i => allSerializers[i]);
}
}
Output:
Trying to serialize without a derived class metadata:
<?xml version="1.0" encoding="utf-16"?>
<Container xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
This error was anticipated,
we have not supplied a derived class.
System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type Program+Derived was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write2_Base(String n, String ns, Base o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_Container(String n, String ns, Container o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write4_Container(Object o)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces)
at Program.Serialize[T](T o)
at Program.Main()
Now trying to serialize with all of the type information:
<?xml version="1.0" encoding="utf-16"?>
<Container xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Base xsi:type="Derived">
<JustSomePropInBase>0</JustSomePropInBase>
<JustSomePropInDerived>0</JustSomePropInDerived>
</Base>
</Container>
Slides down well this time!
Wat zit er in de uitvoer
Deze foutmelding beveelt aan wat we probeerden te vermijden (of wat we in sommige scenario's niet kunnen doen) - verwijzend naar afgeleide types van basisklasse:
Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
Dit is hoe we onze afgeleide klasse in de XML krijgen:
<Base xsi:type="Derived">
Base
komt overeen met het eigenschapstype dat is opgegeven in het Container
type, en Derived
is het type van de daadwerkelijk geleverde instantie.
Hier is een werkvoorbeeld viool