Until last night, I've been parsing XML using a variety of libraries in .NET -- XmlDocument
and XDocument
mostly. I'm not sure why I didn't look into this sooner, but it occurred to me that there must be something available in .NET that gives you class serialization / deserialization for free, and of course that comes in the form of the XmlSerializer
class.
Sure enough, by using a few lines of code, I was able to serialize and deserialize with ease (although in the code I'm currently writing, I only need to deserialize), and no longer had to take the few hours or so to write my own class to do this with other libraries, plus the requisite unit tests. But the problem is that I would like my properties to be read-only. If I make the setter private, then upon creation of the XmlSerializer I get this error:
Unable to generate a temporary class (result=1). error CS0200: Property or indexer 'MyProperty' cannot be assigned to -- it is read only
It looks like this is an issue that won't be resolved, so there must be a workaround.
Sure enough, I found this information, which indicates that you can get the code to compile if you give up auto properties and just back with private fields. Unfortunately, while this compiles, when you execute the code, it doesn't actually deserialize the data. After stopping my application, I noticed several entries in the Messages window that said this:
Could not find schema information for the element 'MyProperty'.
And this is because there's no code to assign a value to MyProperty, because XmlSerializer doesn't know how to deal with private fields!!!
I found an answer on StackOverflow that presents another solution, which is to use a DataContractSerializer
which I hadn't heard of before. I made the necesary code changes to my class, but ended up with the same messages as above. I ran the code to be sure, and the class members don't get set when the XML is deserialized.
I'm thinking that in my particular case, I either suck it up and allow the members to get overwritten (bad), or I go back to my original way of doing things, which is to just write all of the serialization / deserialization code myself. Is there something I'm doing wrong here, or is it impossible to allow a class like XmlSerializer to set private members of a class during deserialization, while making the consumer of the class not be able to overwrite its members?
UPDATE: and yet another article that shows another way to do deserialization of private properties, but I just tried it and it also doesn't work.
Here are some examples of the class that I've tried to deserialize:
[Export]
[DataContract]
public class Configuration
{
[DataMember(Name="Port")]
private int _port;
public int Port { get { return _port; }}
}
Result: when deserializing with the XmlSerializer, there are no errors, but _port and Port have a value of 0 when my XML file has a Port value of 1, e.g. <Port>1</Port>
.
Another example:
[Export]
public class Configuration
{
public int Port { get; set; }
}
Result: deserializes fine, but I don't want a public setter.
I deserialize the class like this:
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
FileStream reader = new FileStream( "config.xml", FileMode.Open);
Configuration Config = (Configuration)serializer.Deserialize( reader);
reader.Close();