Reputation: 3429
I'm trying to serialize an object to XML that has a number of properties, some of which are readonly.
public Guid Id { get; private set; }
I have marked the class [Serializable] and I have implemented the ISerializable interface.
Below is the code I'm using to serialize my object.
public void SaveMyObject(MyObject obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
TextWriter tw = new StreamWriter(_location);
serializer.Serialize(tw, obj);
tw.Close();
}
Unfortunately it falls over on the first line with this message.
InvalidOperationException was unhandled: Unable to generate a temporary class (result=1). error CS0200: Property or indexer 'MyObject.Id' cannot be assigned to -- it is read only
If I set the Id property to public it works fine. Can someone tell me if I'm doing something, or at least if its even possible?
Upvotes: 77
Views: 73252
Reputation: 21289
If you don't need a secure answer, one "good enough" hack is to have a public member, for the sake of serialization, with a name that discourages use in code elsewhere:
// The "real" member used by code. Tell serializer to ignore.
[XMLIgnore]
public Guid Id { get; private set; }
// This is for serializer. Could be named anything. But for humans reading the XML, have XML use the "real" name.
// Give it a member name "SERIALIZER_ONLY_Id" to "discourage" use.
[XmlElement(ElementName = "Id")]
public Guid SERIALIZER_ONLY_Id { get => Id; set => Id = value }
Upvotes: 0
Reputation: 44642
Its not possible with that particular serialization mode (see the other comments for workarounds). If you really want to leave your serialization mode as-is, you have to work around the framework limitations on this one. See this example
Esentially, mark the property public
, but throw an exception if it's accessed at any time other than deserialization.
Upvotes: 0
Reputation: 64628
You could use the System.Runtime.Serialization.NetDataContractSerializer
. It is more powerful and fixes some issues of the classic Xml Serializer.
Note that there are different attributes for this one.
[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 based on Marc's comment: You should probably use System.Runtime.Serialization.DataContractSerializer
for your case to get a clean XML. The rest of the code is the same.
Upvotes: 6
Reputation: 1221
Read only fields will not be serialized using the XmlSerializer
, this is due to the nature of the readonly
keyword
From MSDN:
The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.
So... you would pretty much need to set the fields value in the default constructor...
Upvotes: 2
Reputation: 1063198
You could use DataContractSerializer
(but note you can't use xml attributes - only xml elements):
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);
}
}
}
Alternatively, you can implement IXmlSerializable
and do everything yourself - but this works with XmlSerializer
, at least.
Upvotes: 65