Reputation: 1060
When serializing, how do you handle backer variables? Mine keep on turning up null, as in the following example:
[DataContract]
public Person
{
public Person()
{
//a break point here doesn't get called in time - I try to use _myList and get an exception first. :(
_myList = new string[3];
}
private string[] _myList {get; set;} = new string[3]; // Will be filled: {"Bob", "The", "Builder"};
[DataMember]
public string Occupation
{
get { return _myList[2]; }
set {_myList[2] = value; }
}
}
SerializeFunction(Person Bob, string filePath = @"C:\Temp\BobTheBuilder.xml")
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Person));
using(XmlWriter xmlwriter = XmlWriter.Create(filePath))
{
serializer.WriteObject(xmlWriter, bob);
xmlWriter.Flush();
}
using(XmlReader reader = XmlReader.Create(filePath))
{
// This throws an exception, because _myList is null
Person readInBob = deserializer.ReadObject(xmlReader);
}
}
I get an exception when I try to read Bob back in, because the backer property _myList doesn't get initialized. How do you guys handle situations like this?
Upvotes: 1
Views: 92
Reputation: 1060
If you implement IXmlSerializable
, you gain the control to do whatever you need to. Replace the person class above with:
public Person : IXmlSerializable
{
private string[] _myList {get; set;} = new string[3];
public string Occupation
{
get { return _myList[2]; }
set {_myList[2] = value; }
}
XmlSchema IXmlSerializable.GetSchema() => null;
void IXmlSerializable.ReadXml(XmlReader reader)
{
//THIS IS THE KEY LINE:
_myList = new string[3];// you can do any initialization you need before actually reading.
while(reader.Read())
{
if(reader.NodeType != XmlNoteType.Element)
continue;
string propertyName = reader.Name; // we have arrived at an element.
reader.Read(); // we have the property name, now get it's value
switch(propertyName)
{
case nameof(Occupation):
Occupation = reader.Value; // for an int, you could do: int.Parse(reader.Value);
break;
case "ComplicatedClass": // if you need to serialize complicated class member then you could do this:
// you'd have to not do the reader.Read() above...
// DataContractSerializer complicatedClassSerializer = new DataContractSerializer(typeof(ComplicatedClass));
// ComplicatedClass foo = complicatedClassSerializer.ReadObject(reader) as ComplicatedClass;
break;
}
}
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
writer.WriteElementString(nameof(Occupation), Occupation.ToString());
//for a more complicated type than string, int etc:
//DataContractSerializer complicatedClassSerializer = new DataContractSerializer(typeof(complicatedClass));
//complicatedClassSerializer.WriteObject(writer, new ComplicatedClass());
}
}
Upvotes: 0
Reputation: 1062745
When you do new List<int>(3)
, you are setting the initial capacity, not the number of elements. There are still zero elements, so _myList[0]
etc will all fail until you Add
the appropriate number of elements. This contrasts to arrays, as new int[3]
always has exactly 3 elements (which will be null
initially).
Frankly, there's no need for a list here at all, if you are trying to hard-code them to positions - just use simple properties:
[DataMember]
public string Occupation {get;set;}
Upvotes: 1