2010-11-18 3 views
11

Ich beobachtete ein seltsames Verhalten beim Serialisieren und Deserialisieren einer Klasse, die einen Member vom Typ List<T> hat, der zur Konstruktionszeit mit Standardwerten gefüllt wurde. Im Gegensatz zur Array-basierten Eigenschaft wird die Eigenschaft vom Typ List<T> bei der Deserialisierung durch den XmlSerializer nicht geleert.XmlSerializer und Liste <T> mit Standardwerten

Hier ist mein Code:

public class Program 
{ 
    public class Config 
    { 
     public Config() 
     { 
      Test1 = new List<string>() {"A", "B"}; 
      Test2 = new String[] {"A", "B"}; 
     } 
     public List<string> Test1 {get;set;} 
     public string[] Test2 {get;set;} 
    } 

    public static void Main() 
    { 
     XmlSerializer xmlSerializer = 
      new XmlSerializer(typeof(Config)); 
     using(Stream s = new MemoryStream()) 
     { 
      xmlSerializer.Serialize(s, new Config()); 
      s.Position = 0; 
      xmlSerializer.Serialize(Console.Out, 
       xmlSerializer.Deserialize(s)); 
     } 
    } 
} 

Und dies ist die Ausgabe:

<?xml version="1.0" encoding="ibm850"?> 
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Test1> 
    <string>A</string> 
    <string>B</string> 
    <string>A</string> 
    <string>B</string> 
    </Test1> 
    <Test2> 
    <string>A</string> 
    <string>B</string> 
    </Test2> 
</Config> 

Warum ist die List<T> anders von XmlSerializer als das Array behandelt und was kann ich tun, um dieses Verhalten zu ändern?

+0

ich gleich Problem haben, finden Sie http://stackoverflow.com/questions/5221124/hook-in-to-ondeserializing-for-xmlserializer für Lösung –

+0

Verwandte: http://stackoverflow.com/q/ 13046474/161052 – JYelton

Antwort

5

Interessant; Ich habe das in der Vergangenheit nie bemerkt, aber es ist definitiv reproduzierbar. Da XmlSerializer Serialisierungsrückrufe nicht unterstützt (um Ihnen zu helfen, zu wissen, dass es für die Serialisierung läuft), ist dies schwer zu beeinflussen; wohl die einfachste Antwort lautet: "Setze keine Standarddaten in die Objekte im Konstruktor" (obwohl sie vielleicht eine Factory-Methode anbieten, die das tut).

Sie könnte versuchen, IXmlSerializable zu implementieren, aber das ist übermäßig schwer zu Recht, auch für ein einfaches Beispiel.

Ich habe überprüft, aber, und DataContractSerializernicht nicht auf diese Weise verhalten - so könnte man vielleicht wechseln DataContractSerializer; hier ist mein Testcode mit DCS:

DataContractSerializer ser = 
    new DataContractSerializer(typeof(Config)); 
using (Stream s = new MemoryStream()) 
{ 
    ser.WriteObject(s, new Config()); 
    s.Position = 0; 
    using(var writer = XmlWriter.Create(Console.Out)) { 
     ser.WriteObject(writer, ser.ReadObject(s)); 
    } 
} 

und hier ist das, was ich durch eine die Factory-Methode bedeuten:

public class Config 
{ 
    public Config() 
    { 
     Test1 = new List<string>(); 
     Test2 = nix; 
    } 
    public List<string> Test1 { get; set; } 
    public string[] Test2 { get; set; } 

    private static readonly string[] nix = new string[0]; 
    public static Config CreateDefault() 
    { 
     Config config = new Config(); 
     config.Test1.Add("A"); 
     config.Test1.Add("B"); 
     config.Test2 = new string[2] { "A", "B" }; 
     return config; 
    } 
} 
+0

das ist sehr interessantes Verhalten .... –

3

Dies ist in der Tat frustrierend Verhalten von XML-Deserialisierung wenn Listen eine Reihe von Standardeinträgen enthalten erstellt im Konstruktor.

Meine Problemumgehung war, das XMLIgnoreAttribute auf der Liste zu setzen und ein öffentliches Mitglied des Arrays des Objekttyps mit dem Set/get die Besetzung der Liste aus dem Array zu behandeln.

So etwas wie das Folgende ermöglicht das Erstellen von Standardwerten im Konstruktor, aber verhindert, dass der XML-Serializer Einträge zur Standardliste hinzufügt. (Fehler/keine Validierungen beiseite).

public class Config 
{ 
    public Config() 
    { 
     Test1 = new List<string>() { "A", "B" }; 
     Test2 = new String[] { "A", "B" }; 

    } 

    [XmlIgnore] 
    public List<string> Test1 { get; set; } 
    public string[] Test2 { get; set; } 

    // This member is only to be used during XML serialization 
    public string[] Test1_Array 
    { 
     get 
     { 
      return Test1.ToArray(); 
     } 
     set 
     { 
      Test1 = value.ToList(); 
     } 
    }   

}