Entwickler-Ecke

IO, XML und Registry - Problem mit der Objekt-Serialisierung


Spider - Sa 12.04.08 16:56
Titel: Problem mit der Objekt-Serialisierung
Hi,

ich fizzel mich gerade ein bisschen in C# ein und hab auch gleich das erste Problem ;)

Ich hab folgenden Code:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
namespace PaketDokumentation
{
  public class PacketSpec
  {
    #region Felder
    private int position;
    private TypeMappingEntry type;
    private string name;
    private string desc;
    #endregion

    #region Properties
    [XmlAttribute("Position")]
    public int Position
    {
      get
      {
        return position;
      }
      set
      {
        position = value;
      }
    }

    [XmlAttribute("Type")]
    public TypeMappingEntry Type
    {
      get
      {
        return type;
      }
      set
      {
        type = value;
      }
    }

    [XmlAttribute("Name")]
    public string Name
    {
      get
      {
        return name;
      }
      set
      {
        name = value;
      }
    }

    [XmlAttribute("Desc")]
    public string Desc
    {
      get
      {
        return desc;
      }
      set
      {
        desc = value;
      }
    }
    #endregion
  }

  public class PacketSpecList: List<PacketSpec>
  {}

  public class Packet
  {
    private PacketSpecList speclist = new PacketSpecList();
    private int link;
    private string desc;
    private string name;

    [XmlElement("Specs")]
    public PacketSpecList SpecList
    {
      get
      {
        return speclist;
      }
    }

    [XmlElement("Link")]
    public int Link
    {
      get
      {
        return link;
      }
      set
      {
        link = value;
      }
    }

    [XmlElement("Desc")]
    public string Desc
    {
      get
      {
        return desc;
      }
      set
      {
        desc = value;
      }
    }

    [XmlElement("Name")]
    public string Name
    {
      get
      {
        return name;
      }
      set
      {
        name = value;
      }
    }
  }

  [XmlRoot("Packets")]
  public class Packets: List<Packet>
  {
  }
}


Kurz: Packets -> Packet -> SpecList -> PacketSpec

Jetzt wollte ich die Klasse Packets serialisieren:


C#-Quelltext
1:
2:
3:
4:
5:
 
      XmlSerializer xml = new XmlSerializer(typeof(Packets));
      TextWriter tw = new StreamWriter(@"G:\Test.xml");
      xml.Serialize(tw, Globals.Globals.ClientPackets);
      tw.Close();


Allerdings ernte ich den Fehler, dass die Klasse Packets nicht reflektiert werden konnte. Wenn ich mir dazu die Online-Hilfe anschaue, werde ich auf InvalidOperationException verwiesen, was mich jedoch nicht weiter bringt.

Hat hier jemand eine Idee, wie ich das gerade biegen könnte?

Grüße


Moderiert von user profile iconChristian S.: Topic aus Allgemeine .NET-Fragen verschoben am So 13.04.2008 um 11:55


Kha - Sa 12.04.08 18:32

Folgendes funktioniert bei mir:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
    static void Main(string[] args)
    {
      var s = new XmlSerializer(typeof(Packets));
      s.Serialize(new MemoryStream(), 
        new Packets {
          new Packet {
            Desc = "Mööp",
            // zum Testen writeable gemacht
            SpecList = new PacketSpecList {
              new PacketSpec {
                Desc = "Foo"
              },
              new PacketSpec {
                Desc = "Bar"
              }
            }
          },
          new Packet()
        });
    }

Kannst du die Inner Exception der Ausnahme posten?


Spider - Sa 12.04.08 18:36

Hi,

ich bin mal so frei und poste das ganze Zeugs:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
System.InvalidOperationException wurde nicht behandelt.
  Message="Fehler beim Reflektieren des Typs 'PaketDokumentation.Packets'."
  Source="System.Xml"
  StackTrace:
       bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel)
       bei System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace)
       bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
       bei System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
       bei System.Xml.Serialization.XmlSerializer..ctor(Type type)
       bei PaketDokumentation.fMain.speichernToolStripMenuItem_Click(Object sender, EventArgs e) in F:\!Dokumente\Projekte\MMORPG\Tools\Dokumentationssoftware\PaketDokumentation\PaketDokumentation\fMain.cs:Zeile 101.
       bei System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
       bei System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e)
       bei System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e)
       bei System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
       bei System.Windows.Forms.ToolStripItem.FireEventInteractive(EventArgs e, ToolStripItemEventType met)
       bei System.Windows.Forms.ToolStripItem.FireEvent(EventArgs e, ToolStripItemEventType met)
       bei System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea)
       bei System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
       bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       bei System.Windows.Forms.Control.WndProc(Message& m)
       bei System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       bei System.Windows.Forms.ToolStrip.WndProc(Message& m)
       bei System.Windows.Forms.ToolStripDropDown.WndProc(Message& m)
       bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       bei System.Windows.Forms.Application.Run(Form mainForm)
       bei PaketDokumentation.Program.Main() in F:\!Dokumente\Projekte\MMORPG\Tools\Dokumentationssoftware\PaketDokumentation\PaketDokumentation\Program.cs:Zeile 18.
       bei System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bei System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.InvalidOperationException
       Message="Fehler beim Reflektieren des Typs 'PaketDokumentation.Packet'."
       Source="System.Xml"
       StackTrace:
            bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel)
            bei System.Xml.Serialization.XmlReflectionImporter.CreateArrayElementsFromAttributes(ArrayMapping arrayMapping, XmlArrayItemAttributes attributes, Type arrayElementType, String arrayElementNs)
            bei System.Xml.Serialization.XmlReflectionImporter.ImportArrayLikeMapping(ArrayModel model, String ns)
            bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel)
       InnerException: System.InvalidOperationException
            Message="Fehler beim Reflektieren der Eigenschaft 'SpecList'."
            Source="System.Xml"
            StackTrace:
                 bei System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a)
                 bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel)
            InnerException: System.InvalidOperationException
                 Message="Fehler beim Reflektieren des Typs 'PaketDokumentation.PacketSpec'."
                 Source="System.Xml"
                 StackTrace:
                      bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel)
                      bei System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel)
                      bei System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns)
                      bei System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a)
                 InnerException: System.InvalidOperationException
                      Message="Fehler beim Reflektieren der Eigenschaft 'Type'."
                      Source="System.Xml"
                      StackTrace:
                           bei System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a)
                           bei System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel)
                      InnerException: System.InvalidOperationException
                           Message="Member 'Type' vom Typ PaketDokumentation.TypeMapping.TypeMappingEntry kann nicht serialisiert werden. XmlAttribute/XmlText kann nicht zum Codieren von komplexen Typen verwendet werden."
                           Source="System.Xml"
                           StackTrace:
                                bei System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel)
                                bei System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns)
                                bei System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a)
                           InnerException:


Aber ich sehe es, glaub ich, gerade selbst. Ich hab eine Klasse TypeMapping*, dort hab ich keine XMLElemente definiert.


Hier noch die Klasse TypeMappingEntry:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
public class TypeMappingEntry
  {
    private string name;
    private int size;

    [XmlAttribute("Name")]
    public string Name
    {
      get
      {
        return name;
      }
      set
      {
        name = value;
      }
    }

    [XmlAttribute("Size")]
    public int Size
    {
      get
      {
        return size;
      }
      set
      {
        size = value;
      }
    }
  }


Kha - Sa 12.04.08 18:54

user profile iconSpider hat folgendes geschrieben:
Aber ich sehe es, glaub ich, gerade selbst. Ich hab eine Klasse TypeMapping*, dort hab ich keine XMLElemente definiert.
Bin mir nicht sicher, ob du das richtige meinst, aber die innerste Ausnahme sagt es ja: Du kannst keinen eigenen Typen als Attribut serialisieren, wie sollte das auch im XML aussehen?


Spider - So 13.04.08 11:15

Hi,

ich wollte quasi so einen Aufbau erreichen:


XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
<Packets>
  <ClientPackets>
    <Packet>
      <Specs>
        <Position>1</Position>
        <Type>
          <Name>Byte</Name>
          <Size>1</Size>
        </Type>
        <Name>Test</Name>
        <Desc>-</Desc>
      </Specs>
      <Specs>
        <Position>2</Position>
        <Type>
          <Name>String</Name>
          <Size>30</Size>
        </Type>
        <Name>Test2</Name>
        <Desc>-</Desc>
      </Specs>
      <Name>Ein simples Client-Paket</Name>
      <Link>-1</Link>
      <Desc>Wird beim Verbinden versand</Desc>
    </Packet>
  </ClientPackets>
</Packets>


Natürlich mit beliebig vielen Spezifikationen (<Specs>) und Paketen (<Packet>)


Christian S. - So 13.04.08 11:30

Hallo!

Ein Attribut ist sowas:

XML-Daten
1:
2:
<knoten attribut="42">
</knoten>


Solange die Namen der Knoten in der XML-Datei mit dem Namen der Eigenschaften der Klassen übereinstimmen, brauchst Du ihnen kein Attribut anhängen, dann wird der Name automatisch korrekt gewählt.

Grüße
Christian


UGrohne - So 13.04.08 13:05

Versuch mal nicht mit Klassen zur arbeiten, die von dem generischen Typ List<> erben, sondern diese direkt als Eigenschaft Deiner Klasse zu verwenden. So sparst Du Dir zwei Klassen, es wird übersichtlicher und es könnte sogar funktionieren. Jedenfalls hatte ich bisher beim Serialisieren von List<>-Elementen keine Probleme.


Robert_G - So 13.04.08 13:48

user profile iconUGrohne hat folgendes geschrieben:
Versuch mal nicht mit Klassen zur arbeiten, die von dem generischen Typ List<> erben, sondern diese direkt als Eigenschaft Deiner Klasse zu verwenden. So sparst Du Dir zwei Klassen, es wird übersichtlicher und es könnte sogar funktionieren. Jedenfalls hatte ich bisher beim Serialisieren von List<>-Elementen keine Probleme.
Das ist zwar absolut richtig, und genauso sollte er sich mal von FxCop erklären lassen, dass seine Benennungen zu Hirnblutungen führen können.
Aber das eigentliche Problem war, dass er versuchte, einen Komposittypen als Attribute zu serialisieren. Da ein Attribut nur einen einzigen Wert enthalten kann, ist das wohl etwas schwierig...


UGrohne - So 13.04.08 14:03

user profile iconRobert_G hat folgendes geschrieben:
user profile iconUGrohne hat folgendes geschrieben:
Versuch mal nicht mit Klassen zur arbeiten, die von dem generischen Typ List<> erben, sondern diese direkt als Eigenschaft Deiner Klasse zu verwenden. So sparst Du Dir zwei Klassen, es wird übersichtlicher und es könnte sogar funktionieren. Jedenfalls hatte ich bisher beim Serialisieren von List<>-Elementen keine Probleme.
Das ist zwar absolut richtig, und genauso sollte er sich mal von FxCop erklären lassen, dass seine Benennungen zu Hirnblutungen führen können.
Aber das eigentliche Problem war, dass er versuchte, einen Komposittypen als Attribute zu serialisieren. Da ein Attribut nur einen einzigen Wert enthalten kann, ist das wohl etwas schwierig...

Stimmt, kommt wohl davon, wenn man nicht alles genau durchliest, sondern sich nebenher um seine Server kümmert :oops: ;)