2009-04-29 14 views
71

Ich versuche, ein Objekt zu XML zu serialisieren, das eine Reihe von Eigenschaften hat, von denen einige schreibgeschützt sind.Serialisierung von privaten Mitgliedsdaten

public Guid Id { get; private set; } 

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

Unten ist der Code, den ich verwende, um mein Objekt zu serialisieren.

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 auf die erste Zeile mit dieser Nachricht.

Die InvalidOperationException wurde nicht behandelt: Es konnte keine temporäre Klasse generiert werden (Ergebnis = 1). Fehler CS0200: Eigenschaft oder Indexer ‚MyObject.Id‘ kann nicht zugeordnet werden - es ist nur

gelesen Wenn ich die Id-Eigenschaft auf public eingestellt es funktioniert gut. Kann mir jemand sagen, ob ich etwas tue oder zumindest wenn es überhaupt möglich ist?

Antwort

57

könnten Sie verwenden DataContractSerializer (aber beachten Sie xml nicht 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 Sie IXmlSerializable implementieren können und tun alles selbst - aber das funktioniert mit XmlSerializer, zumindest .

+0

+1, danke für den Hinweis auf meine Antwort. –

+0

Ich habe meinen Code geändert, um den DataContractSerializer zu verwenden, und habe festgestellt, dass die GetObjectData-Methode weiterhin ausgeführt wird. Habe ich Recht damit, dass ich entweder Attribute auf meine Eigenschaften setzen kann, um sie zu serialisieren, oder kann ich die ISerializable-Schnittstelle implementieren? –

+0

Wenn Sie ISerializable implementieren (oder ist es IXmlSealizable?), Erledigen Sie im Grunde alle die Arbeit selbst ... –

6

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

Beachten Sie, dass es verschiedene Attribute für dieses 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); 

Edit:

-Update auf Basis von Marcs Kommentar: Sie wahrscheinlich System.Runtime.Serialization.DataContractSerializer für Ihren Fall verwenden sollten eine saubere XML zu erhalten. Der Rest des Codes ist der gleiche.

+0

NetDataContractSerializer schreibt nicht xml ... - oder vielmehr ist es nicht sauber xml für den externen Verbrauch geeignet - es hat Assembly-Metadaten drin. –

+0

@Marc: Danke für den Hinweis. Es kommt immer darauf an, was man erreichen will. DataContractSerializer ist wahrscheinlich, was hier erwartet wird. –

1

nur lesen Felder nicht die XmlSerializer mit serialisiert werden, dies auf die Art des readonly Schlüsselwort gebührt

Von MSDN:

Die Nur-Lese- Schlüsselwort ist ein Modifikator, die Sie verwenden können, auf Feldern. Wenn eine Felddeklaration einen readonly-Modifizierer enthält, können Zuordnungen zu den Feldern, die von der Deklaration eingeführt werden, nur als Teil der Deklaration oder in einem Konstruktor in derselben Klasse auftreten.

So ... Sie müssen so ziemlich die Felder Wert in dem Default-Konstruktor setzen ...

+0

Ich dachte, dass, weil ich die ISerializable.GetObjectData Methode implementiert hatte der XmlSerializer das verwenden würde, um die Informationen zu erhalten, die ich serialisieren wollte, und nicht versuchen, auf meine schreibgeschützten Eigenschaften zuzugreifen . –

+0

XmlSerializer kümmert sich nicht um ISerializable - nur IXmlSerializable –

+0

Marc danke, das macht Sinn. –

0

Es ist nicht möglich, mit diesem speziellen Serialisierung-Modus (die anderen Kommentare zu Abhilfen sehen). Wenn Sie Ihren Serialisierungsmodus wirklich unverändert lassen möchten, müssen Sie die Framework-Einschränkungen umgehen.Siehe example

Im Wesentlichen markieren Sie die Eigenschaft public, aber werfen Sie eine Ausnahme, wenn es zu einem anderen Zeitpunkt als Deserialisierung zugegriffen wird.

+5

"aber eine Ausnahme auslösen" - Da XmlSerializer Serialisierungsrückrufe nicht unterstützt, haben Sie keine Möglichkeit zu wissen ... –

+1

Sie könnten 'System.Diagnostics.StackTrace' verwenden, um herauszufinden, was Ihre Eigenschaft aufruft, aber ich würde nicht empfehle eine solche Lösung :-) –

Verwandte Themen