2010-07-24 5 views
12

Hallo Ich versuche, ein Array von Objekten zu serialisieren, die von einer Klasse abgeleitet sind, und ich treffe den gleichen Fehler mit C#. Jede Hilfe wird sehr geschätzt.C# XML-Serialisierung von abgeleiteten Klassen

offensichtlich wurde dieses Beispiel für den Zweck dieser Post in der realen Welt verkleinert Shape würde eine Fülle von verschiedenen Formen enthalten.

Program.cs

namespace XMLInheritTests 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Shape[] a = new Shape[1] { new Square(1) }; 

      FileStream fS = new FileStream("C:\\shape.xml", 
             FileMode.OpenOrCreate); 
      XmlSerializer xS = new XmlSerializer(a.GetType()); 
      Console.WriteLine("writing"); 
      try 
      { 
       xS.Serialize(fS, a); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.InnerException.ToString()); 
       Console.ReadKey(); 
      } 
      fS.Close(); 
      Console.WriteLine("Fin"); 
     } 
    } 
} 

Shape.cs

namespace XMLInheritTests 
{ 
    public abstract class Shape 
    { 
     public Shape() { } 
     public int area; 
     public int edges; 
    } 
} 

Square.cs

namespace XMLInheritTests 
{ 
    public class Square : Shape 
    { 
     public int iSize; 
     public Square() { } 

     public Square(int size) 
     { 
      iSize = size; 
      edges = 4; 
      area = size * size; 
     } 
    } 
} 

Fehler: System.InvalidOperationException: Der Typ XMLInheritTests.Square war nicht zu erwarten. Verwenden Sie das XmlInclude- oder SoapInclude-Attribut, um Typen anzugeben, die statisch nicht bekannt sind.

bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterShapeA rray.Write2_Shape (String n, String ns, Form o, Boolean isNullable, Boolean müssen Typ)

bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterShapeA rray.Write3_ArrayOfShape (Object o)

Vielen Dank

+2

Als eine Seite, öffentliche Felder sind * in der Regel * zu vermeiden; Eine 'public int Size {get; set;}' wäre vorzuziehen. –

+0

Sie könnten * auch * die Kanten und die Größe als virtuelle 'get'-Eigenschaften haben, so dass Sie sie nicht ** speichern müssen. –

Antwort

19
[XmlInclude(typeof(Square))] 
public abstract class Shape {...} 

(Wiederholung für alle bekannten Subtypen)

Wenn die Typen nur zur Laufzeit bekannt sind, können Sie sie dem XmlSerializer-Konstruktor übergeben, aber: dann ist wichtig, zu cachen und diese Serializer-Instanz wiederzuverwenden; Andernfalls bluten Sie dynamisch erzeugte Assemblys. Dies geschieht automatisch, wenn Sie den Konstruktor verwenden, der nur eine Type, aber nicht für die anderen Überladungen verwendet.

+0

Cool Ich denke, ich habe das funktioniert (für jetzt: S), vielen Dank – 111111

+0

Ehrfürchtig, wie würde ich dies für mehrere geerbte Klassen tun. (Beispiel mit dem Thema der Formen) Shape-> Square-> ColoredSquare? –

+0

Sie haben geschrieben: 'aber: ** dann ** ist es wichtig, diese Serializer-Instanz zu cachen und wiederzuverwenden ...' (meine Betonung). Ihre Argumentation hängt vom Konstruktor ab, nicht vom Typ, der dynamisch geliefert wird. Oder habe ich etwas vermisst? – ispiro

3

Lösung:

class Program 
    { 
     static void Main(string[] args) 
     { 
      Shape[] a = new Shape[2] { new Square(1), new Triangle() }; 

      FileStream fS = new FileStream("C:\\shape.xml",FileMode.OpenOrCreate); 

      //this could be much cleaner 
      Type[] t = { a[1].GetType(), a[0].GetType() }; 


      XmlSerializer xS = new XmlSerializer(a.GetType(),t); 
      Console.WriteLine("writing"); 
      try 
      { 
       xS.Serialize(fS, a); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.InnerException.ToString()); 
       Console.ReadKey(); 
      } 
      fS.Close(); 
      Console.WriteLine("Fin"); 
     } 
    } 

namespace XMLInheritTests 
{ 
    [XmlInclude(typeof(Square))] 
    [XmlInclude(typeof(Triangle))] 
    public abstract class Shape 
    { 
     public Shape() { } 
     public int area; 
     public int edges; 
    } 
} 

Dank; Ich werde ohne Zweifel sehr bald ein anderes Problem haben: S