Suche…


Bemerkungen

Verwenden Sie den XmlSerializer zum Parsen von HTML . Dafür stehen spezielle Bibliotheken wie das HTML Agility Pack zur Verfügung

Objekt serialisieren

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);
    }
}

Objekt deserialisieren

public Foo DeserializeFoo(string fileName)
{
    var serializer = new XmlSerializer(typeof(Foo));
    using (var stream = File.OpenRead(fileName))
    {
        return (Foo)serializer.Deserialize(stream);
    }
}

Verhalten: Ordnen Sie den Elementnamen der Eigenschaft zu

<Foo>
    <Dog/>
</Foo>
public class Foo
{
    // Using XmlElement
    [XmlElement(Name="Dog")]
    public Animal Cat { get; set; }
}

Verhalten: Ordnen Sie den Arraynamen der Eigenschaft zu (XmlArray).

<Store>
    <Articles>
        <Product/>
        <Product/>
    </Articles>
</Store>
public class Store
{
    [XmlArray("Articles")]
    public List<Product> Products {get; set; }
}

Formatierung: Benutzerdefiniertes DateTime-Format

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); }
    }
}

Effizientes Erstellen mehrerer Serialisierer mit dynamisch festgelegten abgeleiteten Typen

Woher wir kamen

Manchmal können wir nicht alle erforderlichen Metadaten bereitstellen, die für das XmlSerializer-Framework in Attribut erforderlich sind. Nehmen wir an, wir haben eine Basisklasse von serialisierten Objekten, und einige der abgeleiteten Klassen sind der Basisklasse unbekannt. Wir können kein Attribut für alle Klassen platzieren, die zum Entwurfszeitpunkt des Basistyps nicht bekannt sind. Wir könnten ein anderes Team haben, das einige der abgeleiteten Klassen entwickelt.

Was können wir tun

Wir können den new XmlSerializer(type, knownTypes) , aber das wäre eine O (N ^ 2) new XmlSerializer(type, knownTypes) für N Serialisierer, um zumindest alle in Argumenten angegebenen Typen zu ermitteln:

// 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 diesem Beispiel kennt der Basistyp die abgeleiteten Typen nicht, was in OOP normal ist.

Effizient machen

Glücklicherweise gibt es eine Methode, die dieses spezielle Problem anspricht - bekannte Typen für mehrere Serialisierer effizient bereitzustellen:

System.Xml.Serialization.XmlSerializer.FromTypes-Methode (Typ [])

Mit der FromTypes-Methode können Sie effizient ein Array von XmlSerializer-Objekten zum Verarbeiten eines Arrays von Type-Objekten erstellen.

var allSerializers = XmlSerializer.FromTypes(allTypes);
var serializerDictionary = Enumerable.Range(0, allTypes.Length)
    .ToDictionary(i => allTypes[i], i => allSerializers[i]);

Hier ist ein komplettes Codebeispiel:

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]);
    }
}

Ausgabe:

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!

Was ist in der Ausgabe?

In dieser Fehlermeldung wird empfohlen, was wir vermeiden wollten (oder was wir in einigen Szenarien nicht tun können). Dabei werden abgeleitete Typen aus der Basisklasse referenziert:

Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

So bekommen wir unsere abgeleitete Klasse im XML:

<Base xsi:type="Derived">

Base entspricht dem im Container deklarierten Eigenschaftstyp. Derived ist der Typ der tatsächlich gelieferten Instanz.

Hier ist eine Arbeitsbeispiel- Geige



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow