Serialisierung privater Mitgliedsdaten

74

Ich versuche, ein Objekt in XML zu serialisieren, das eine Reihe von Eigenschaften aufweist, von denen einige schreibgeschützt sind.

public Guid Id { get; private set; }

Ich habe die Klasse [Serializable] markiert und die ISerializable-Schnittstelle implementiert.

Unten ist der Code, mit dem ich mein Objekt serialisiere.

public void SaveMyObject(MyObject obj)
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
    TextWriter tw = new StreamWriter(_location);
    serializer.Serialize(tw, obj);
    tw.Close();
}

Leider fällt es in der ersten Zeile mit dieser Nachricht um.

InvalidOperationException wurde nicht behandelt: Es konnte keine temporäre Klasse generiert werden (Ergebnis = 1). Fehler CS0200: Eigenschaft oder Indexer 'MyObject.Id' kann nicht zugewiesen werden - es ist schreibgeschützt

Wenn ich die Id-Eigenschaft auf public setze, funktioniert sie einwandfrei. Kann mir jemand sagen, ob ich etwas mache oder ob es überhaupt möglich ist?

Jon Mitchell
quelle

Antworten:

62

Sie könnten verwenden DataContractSerializer(aber beachten Sie, dass Sie keine XML-Attribute verwenden können - nur XML-Elemente):

using System;
using System.Runtime.Serialization;
using System.Xml;
[DataContract]
class MyObject {
    public MyObject(Guid id) { this.id = id; }
    [DataMember(Name="Id")]
    private Guid id;
    public Guid Id { get {return id;}}
}
static class Program {
    static void Main() {
        var ser = new DataContractSerializer(typeof(MyObject));
        var obj = new MyObject(Guid.NewGuid());
        using(XmlWriter xw = XmlWriter.Create(Console.Out)) {
            ser.WriteObject(xw, obj);
        }
    }
}

Alternativ können Sie IXmlSerializablealles selbst implementieren und ausführen - aber das funktioniert XmlSerializerzumindest.

Marc Gravell
quelle
Ich habe meinen Code geändert, um den DataContractSerializer zu verwenden, und festgestellt, dass die GetObjectData-Methode weiterhin ausgeführt wird. Habe ich Recht, wenn ich denke, dass ich meinen Eigenschaften entweder Attribute zuweisen kann, um sie zu serialisieren, oder die ISerializable-Schnittstelle implementieren kann?
Jon Mitchell
Wenn Sie ISerializable implementieren (oder ist es IXmlSeializable?), Machen Sie die ganze Arbeit im Grunde selbst ...
Marc Gravell
4
Dies funktionierte für mich, aber später stellte ich fest, dass das Serialisieren privater Mitglieder mit dem DataMemberAttribute nur funktioniert, wenn es in einer Umgebung mit vollständiger Vertrauenswürdigkeit ausgeführt wird, nicht mit teilweiser Vertrauenswürdigkeit. Eine Lösung besteht darin, das Mitglied intern statt privat zu machen. Für Details siehe blog.walteralmeida.com/2010/05/… .
Peladao
6

Sie könnten die verwenden System.Runtime.Serialization.NetDataContractSerializer. Es ist leistungsfähiger und behebt einige Probleme des klassischen Xml Serializer.

Beachten Sie, dass es für dieses Attribut unterschiedliche Attribute gibt.

[DataContract]
public class X
{
  [DataMember]
  public Guid Id { get; private set; }
}


NetDataContractSerializer serializer = new NetDataContractSerializer();
TextWriter tw = new StreamWriter(_location);
serializer.Serialize(tw, obj);

Bearbeiten:

Update basierend auf Marc's Kommentar: Sie sollten es wahrscheinlich System.Runtime.Serialization.DataContractSerializerfür Ihren Fall verwenden, um ein sauberes XML zu erhalten. Der Rest des Codes ist der gleiche.

Stefan Steinegger
quelle
NetDataContractSerializer schreibt keine XML ... - oder besser gesagt, es ist keine saubere XML, die für den externen Verbrauch geeignet ist - es enthält Assembly-Metadaten.
Marc Gravell
@ Marc: Danke für den Hinweis. Es kommt immer darauf an, was man erreichen will. DataContractSerializer ist wahrscheinlich das, was hier erwartet wird.
Stefan Steinegger
2

Schreibgeschützte Felder werden nicht mit dem serialisiert XmlSerializer. Dies liegt an der Art des readonlySchlüsselworts

Von MSDN:

Das Schlüsselwort readonly ist ein Modifikator, den Sie für Felder verwenden können. Wenn eine Felddeklaration einen schreibgeschützten Modifikator enthält, können Zuweisungen zu den durch die Deklaration eingeführten Feldern nur als Teil der Deklaration oder in einem Konstruktor derselben Klasse erfolgen.

Also ... Sie müssten so ziemlich den Feldwert im Standardkonstruktor festlegen ...

flalar
quelle
Ich dachte, da ich die ISerializable.GetObjectData-Methode implementiert hatte, würde der XmlSerializer diese verwenden, um die Informationen abzurufen, die ich serialisieren wollte, und nicht versuchen, auf meine schreibgeschützten Eigenschaften zuzugreifen.
Jon Mitchell
XmlSerializer kümmert sich nicht um ISerializable - nur IXmlSerializable
Marc Gravell
0

Mit diesem speziellen Serialisierungsmodus ist dies nicht möglich (Problemumgehungen finden Sie in den anderen Kommentaren). Wenn Sie Ihren Serialisierungsmodus wirklich unverändert lassen möchten, müssen Sie die Framework-Einschränkungen in diesem Fall umgehen. Siehe dieses Beispiel

Markieren Sie die Eigenschaft im Wesentlichen, lösen Sie publicjedoch eine Ausnahme aus, wenn zu einem anderen Zeitpunkt als der Deserialisierung darauf zugegriffen wird.

jvenema
quelle
5
"aber eine Ausnahme auslösen" - da XmlSerializer keine Serialisierungsrückrufe unterstützt, können Sie nicht wissen ...
Marc Gravell
1
Sie könnten System.Diagnostics.StackTraceherausfinden, wie Ihre Immobilie heißt, aber ich würde eine solche Lösung nicht empfehlen :-)
Louis Somers