I have a class with some collections in them, and I would like to serialize instances of this class to XML without having to initialize the collections to be empty, and without having to implement IXmlSerializable. I don't care if it creates empty elements, or doesn't create the elements at all. Just that it works without having to initialize a collection for each collection based property.
I have look at all the XML attributes I can decorate the properties with, and have not had any success with this. This seems like a simple thing to do that is can have an element or just none at all. Then when it is being deserialized it would just leave them null or ignore them period.
Here is a simple version of a class to use for working through this issue. Using this and the defaults you get an exception "Object reference not set to an instance of an object" due to the collections being null;
public class MyClass
{
public string Name { get; set; }
public bool IsAlive { get; set; }
public List<Car> Cars { get; set; }
public List<Home> Homes { get; set; }
public List<Pet> Pets { get; set; }
public void ToXmlFile(string fileName)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
TextWriter writer = new StreamWriter(fileName);
serializer.Serialize(writer, this);
writer.Close();
}
}
EDIT
Thanks for the helps guys, it turns out the issue was in my GetHashCode method which didn't handle the null correctly. Once I fixed this all was good. I marked the first one to answer as being correct. Sorry for the Red Herring, but working through it with you guys did help.
You do not need to initialize collections in order to serialize the class to XML. Here's a simple program to demonstrate:
class Program
{
static void Main(string[] args)
{
MyClass c = new MyClass() { Name = "Test", IsAlive = true };
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
using (MemoryStream ms = new MemoryStream())
{
serializer.Serialize(ms, c);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}
Console.ReadLine();
}
}
This will print the following output:
<?xml version="1.0"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Test</Name>
<IsAlive>true</IsAlive>
</MyClass>
In other words, null collection properties behave the same way as any other null property - they don't get serialized at all (unless you change the default value, which I haven't).
You can serialize this without a problem only you have to send the types of car, home and pet when you serialize in the extraTypes parameter.
You mention an exception during (de)serialization; what you have should work OK (at least, according to how you define the question). I wonder if you actually have:
public class MyClass
{
public string Name { get; set; }
public bool IsAlive { get; set; }
public List<Car> Cars { get; private set; }
public List<Home> Homes { get; private set; }
public List<Pet> Pets { get; private set; }
}
(not uncommon to not want a public setter)
Well, XmlSerializer is fussy about this; you either need a public setter, or (as somebody pointed out recently) no setter; for example:
public class MyClass
{
public string Name { get; set; }
public bool IsAlive { get; set; }
private readonly List<Car> cars = new List<Car>();
public List<Car> Cars { get { return cars; } }
private readonly List<Home> homes = new List<Home>();
public List<Home> Homes { get { return homes; } }
private readonly List<Pet> pets = new List<Pet>();
public List<Pet> Pets { get { return pets; } }
}
I think setting the return type of the XMLSerialisation method to a bool would allow you to handle errors in a safer fashion as opposed to the current method:
public bool ToXmlFile(string fileName)
{
if(fileName != "")
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
TextWriter writer = new StreamWriter(fileName);
serializer.Serialize(writer, this);
writer.Close();
return true;
}
return false;
}
Which can then be used like so:
if(ToXMLFile)
{
MessageBox.Show("Save Succesful");
}
else
(
MessageBox.Show("Save unsuccesful");
)
This is merely a crude example however i have used a similar method in my own applications when loading or saving data and it works well, also a good visual indicator for the end user.
Related
I have a ApplicationSettingsBase object I use to save user preferences, as well as application settings. For all of my built-in types, it properly serializes to XML and I get a nice user-editable config file. However, for my custom type "RuleCollection", this doesn't work, the only way for me to serialize it is binary which is nonsense to the user.
I have tried from the following links without success:
Add a collection of a custom class to Settings.Settings -- I originally was trying to serialize a CleanRule[] as I was able to serialize a string[] without issue. Adding the collection class as a wrapper was a band-aid that didn't work.
Custom Xml Serialization of Unknown Type and Implementing Custom XML Serialization/Deserialization of compound data type? -- I wasn't able to make settings.Save() trigger the custom XML Read/Write classes from implementing IXmlSerializable, I think if I could force it to, this would work.
What I'm hoping for is a nice XML output where I have something like
-> Collection
-> Rule 1
-> Title
-> Description
-> Enabled
-> Mode
-> Regex
-> Args
-> Arg1
-> Arg2
-> Rule 2
-> Title
-> Description
-> Enabled
-> Mode
-> Regex
-> Args
-> Arg1
I am using .NET Framework 4.7.2
public class UserSettings : ApplicationSettingsBase
{
[UserScopedSetting]
[SettingsSerializeAs(SettingsSerializeAs.Binary)]
public RuleCollection Rules
{
get { return (RuleCollection)this["Rules"]; }
set { this["Rules"] = value; }
}
... //other properties
}
Below is the properties of the RuleCollection and CleanRule classes, CleanMode is an `Enum
[Serializable]
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class CleanRule
{
public string Title { get; private set; }
public string Description { get; private set; }
public bool Enabled { get; private set; } = true;
public CleanMode Mode { get; private set; }
public Regex R { get; private set; }
public string[] Args { get; private set; }
... //constructors and other methods
}
[Serializable]
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class RuleCollection : IEnumerable<CleanRule>
{
public List<CleanRule> Rules { get; set; }
... // constructors and other methods
}
Finally, I am editing and saving the property like so
settings = new UserSettings();
settings.Rules = settings.Rules ?? new RuleCollection();
settings.Save();
and
RuleForm rf = new RuleForm(settings.Rules);
if(rf.ShowDialog(this) == DialogResult.OK)
{
settings.Rules = rf.Rules;
settings.Save();
}
EDIT:
I've boiled this down to a more simple example
EDIT 2:
This example now works, it was missing a no-arg constructor as per How to serialize a class with a list of custom objects? My main code is still not working, but it would appear that serialization errors are being masked by the ApplicationSettingsBase class
public class UserSettings : ApplicationSettingsBase
{
[UserScopedSetting]
public Test Test
{
get { return (Test)this["Test"]; }
set { this["Test"] = value; }
}
}
[Serializable]
public class Test
{
public int I { get; set; }
public string S { get; set; }
public Test(){ }
public Test(int i, string s)
{
I = i;
S = s;
}
}
settings = new UserSettings();
settings.Test = new Test(30, "Tom");
settings.Save();
Result:
<setting name="Test" serializeAs="Xml">
<value>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<I>30</I>
<S>Tom</S>
</Test>
</value>
</setting>
TL:DR; there were a bunch of little things wrong that SHOULD HAVE been raised as exceptions, however, due to using the ApplicationSettingsBase class, serialization errors were being suppressed.
I found a post that gave me explicit "write to" and "read from" xml file for a generic type <T> and used that to force the object I was having trouble with to xml and raise those errors.
public static void WriteToXmlFile<T>(string filePath, T objectTowrite, bool append = false) where T : new()
{
TextWriter writer = null;
try
{
var serializer = new XmlSerializer(typeof(T));
writer = new StreamWriter(filePath, append);
serializer.Serialize(writer, objectTowrite);
}
finally
{
if (writer != null)
writer.Close();
}
}
public static T ReadFromXmlFile<T>(string filePath) where T : new()
{
TextReader reader = null;
try
{
var serializer = new XmlSerializer(typeof(T));
reader = new StreamReader(filePath);
return (T)serializer.Deserialize(reader);
}
finally
{
if (reader != null)
reader.Close();
}
}
The first error had to do with my collection function inheriting from IEnumerable but not implementing Add()
public class RuleCollection : IEnumerable<CleanRule>
{
[XmlArray]
public List<CleanRule> Rules { get; set; }
public RuleCollection(){ ... }
public RuleCollection(IEnumerable<CleanRule> rules){ ... }
public void Add(CleanRule rule){ ... }
public void Remove(CleanRule rule){ ... }
public void Enable(CleanRule rule){ ... }
public void Disable(CleanRule rule){ ... }
}
The second error was that my classes attributes had private setters. I'm not crazy about those being public but I guess that's just what has to happen.
public class CleanRule
{
public string Title { get; set; }
public string Description { get; set; }
...
}
And I'm still working on the third error, which is serialization of a Regex object.
I'm trying to set up a very small database using XML serialization and more specifically XmlSerializer.
My main class is the following :
public class XmlDB
{
[XmlIgnore]
public string FilePath { get; private set; }
public List<FooType> Foos { get; set; }
public List<BarType> Bars { get; set; }
public List<ThirdType> Thirds { get; set; }
private XmlDB():this(null) { }
public XmlDB(string strDBPath) {
this.FilePath = strDBPath;
this.Foos = new List<FooType>();
this.Bars = new List<BarType>();
this.Thirds = new List<ThirdType>();
}
public static XmlDB Load(string strDBPath) {
using (XmlReader reader = XmlReader.Create(strDBPath)) {
XmlDB db = (XmlDB)new XmlSerializer(typeof(XmlDB)).Deserialize(reader);
db.FilePath = strDBPath;
return db;
}
}
public void SaveChanges() {
XmlWriterSettings settings = new XmlWriterSettings() {
Indent = true,
Encoding = Encoding.UTF8
};
using (XmlWriter writer = XmlWriter.Create(this.FilePath, settings)) {
XmlSerializer ser = new XmlSerializer(typeof(XmlDB));
ser.Serialize(writer, this);
}
}
}
My test method creates an instance, populates the lists and calls the SaveChanges method.
Everything works fine on serialization and the Xml output looks consistent.
The problem happens on deserializing : No error is reported but only the first item of the first List is treated, the following items of the first list are not deserialized, neither are the following lists...
If I shuffle the order of the lists in the Xml, it's always the first item of the first list in the Xml file that is deserialized.
I tried the following simple test to confirm (which unfortunately works fine, all lists are populated on deserializing) :
public class DBTestList
{
public List<DBTest> TestList { get; set; }
public List<DBTest2> TestList2 { get; set; }
public DBTestList() {
this.TestList = new List<DBTest>();
this.TestList2 = new List<DBTest2>();
}
}
public class DBTest
{
public int TestInt { get; set; }
public string TestStr { get; set; }
}
public class DBTest2
{
public int TestInt { get; set; }
public string TestStr { get; set; }
}
public void TestSerialProblem() {
//Init data
DBTestList tl = new DBTestList();
tl.TestList.Add(new DBTest() { TestInt = 1, TestStr = "test11" });
tl.TestList.Add(new DBTest() { TestInt = 2, TestStr = "test12" });
tl.TestList2.Add(new DBTest2() { TestInt = 3, TestStr = "test21" });
XmlWriterSettings settings = new XmlWriterSettings() {
Indent = true,
Encoding = Encoding.UTF8
};
using (XmlWriter writer = XmlWriter.Create("test.db", settings)) {
XmlSerializer ser = new XmlSerializer(typeof(DBTestList));
ser.Serialize(writer, tl);
}
using (XmlReader reader = XmlReader.Create("test.db")) {
DBTestList db = (DBTestList)new XmlSerializer(typeof(DBTestList)).Deserialize(reader);
Assert.IsTrue(db.TestList2[0].TestStr == "test21");
}
}
I read a lot of posts on this subject but none helped.
Do you have an idea ?
Thanks,
Best regards.
EDIT :
To give a more detailed idea of the classes used in the lists, here's one basic implementation.
All the types are derived from the parent one a_SolidElement, adding only a few properties (basic value types and/or enum) :
public abstract class a_SolidElement
{
[XmlIgnore]
public int Position { get; set; }
public virtual double Thickness { get; set; }
public virtual double Density { get; set; }
public string SupplierName { get; set; }
public string Name { get; set; }
}
public enum ElementType
{
Undefined=0,
TypeA,
TypeB
}
public class FooType:a_SolidElement
{
public double AdditionalData { get; set; }
public e_ElementType ElementType { get; set; }
}
dbc was actually right about the bad IXmlSerializable implementation in his comment :
In one of my classes, I had one property of a type I didn't write, with a problem in the readXml method.
I didn't see it at first because I successively removed some properties to see which one caused the problem but this one was still in the first deserialized item so that even if the subsequent ones didn't have it, the reader was still already messed up by the first one.
It's so obvious now that I feel bad for asking the question in the first place !
Thank you very much for the help !
I am trying to deserialise an RSS 2.0 feed and i would like to take into account some of the iTunes extensions, but not have to bake them directly into the main class.
With the XML deserialiser in C# would something like the following be possible?
public class RssChannel
{
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("link")]
public string Link { get; set; }
....
[XmlElement(Namespace = "itunes")]
public iTunesExtensions iTunes { get; set; }
}
public class iTunesExtensions
{
[XmlElement("category")]
public string[] Categories { get; set; }
}
Which i am hoping would parse something like:
<channel>
<itunes:category text="Society & Culture"/>
<itunes:category text="Society & Culture"/>
<itunes:category text="Society & Culture"/>
</channel>
Is it possible to do something like this where it is more modular? Or am i stuck baking it into the main class?
bizzehdee,
In order to set the first level to "", you would need to set it as the root and name of your class:
[XmlRoot("channel")]
public class channel
I will keep it as RssChannel, for the following examples.
I am assuming you intend to use more platforms than iTunes, so iTunes still has its own class. The way to do this, with less code, is to use a list instead of an array:
public List<iTunes> iTunes;
Categories will have its own class, so that you can use categories with any platform. Notice the use of XmlAttribute. This will include the name of the category in the same line:
public class iTunes
{
public List<Category> Categories { get; set; }
}
public class Category
{
[XmlAttribute("category")]
public string category { get; set; }
}
You can use a static class to help you serialize and deserialize the data. Here are two methods in a static class that will help:
// Save XML data.
public static void SaveData(ref RssChannel instance) {}
// Retrieve XML data.
public static RssChannel DeserializeData() {}
The best way to use these methods is to first get an instance of the RssChannel with the DeserializeData() method, like:
RssChannel foo = StaticClassName.DeserializeData();
Make your changes to it, then save that instance by passing it as a reference to the SaveData() method, like:
SaveData(ref foo);
Here is a full working example:
public static class XML
{
// Serializes the passed instance of RssChannel into XML file, and saves to runtime memory.
public static void SaveData(ref RssChannel instance)
{
// Objects:
StreamWriter sw = new StreamWriter("yourXmlFile.xml");
XmlSerializer serializer = new XmlSerializer(typeof(RssChannel));
// Save data.
serializer.Serialize(sw, instance);
sw.Close();
}
// Deserializes data from the XML file, and returns the instance.
public static RssChannel DeserializeData()
{
// Objects:
RssChannel channelData = new RssChannel();
XmlSerializer serializer = new XmlSerializer(typeof(RssChannel));
List<iTunes> iTunesList = new List<iTunes>();
if (File.Exists("yourXmlFile.xml"))
{
FileStream stream = new FileStream("yourXmlFile.xml", FileMode.Open);
// Deserialize data.
channelData = (RssChannel)serializer.Deserialize(stream);
stream.Close();
// Add data from deserialized iTunes list to list instance.
if (channelData.iTunesList != null)
iTunesList = channelData.iTunesList;
}
// Add data to RootData object lists.
channelData.iTunesList = iTunesList;
return channelData;
}
}
[XmlRoot("RssChannel")]
public class RssChannel
{
[XmlAttribute("Title")]
public string Title; // { get; set; }
[XmlAttribute("Link")]
public string Link; // { get; set; }
public List<iTunes> iTunesList; // { get; set; }
}
public class iTunes
{
public List<Category> Categories; // { get; set; }
}
public class Category
{
[XmlAttribute("category")]
public string category; // { get; set; }
}
You can use the classes and static methods like this:
private void AnyMethod()
{
// To get an instance of your RssChannel class with all the data:
RssChannel rssChannel = XML.DeserializeData();
// Do anything with the data. Example below:
iTunes newITunes = new iTunes();
List<Category> categoryList = new List<Category>();
Category newCategory1 = new Category(); // Create new categories.
newCategory1.category = "Allegro";
categoryList.Add(newCategory1);
Category newCategory2 = new Category();
newCategory2.category = "Prestissimo";
categoryList.Add(newCategory2);
newITunes.Categories = categoryList; // Add the categories to list.
rssChannel.iTunesList.Add(newITunes); // Add that list to iTunes list.
// Now, to save the data, pass a reference to the instance we just worked on:
XML.SaveData(ref rssChannel);
}
This will produce a file that looks like:
<?xml version="1.0" encoding="utf-8"?>
<RssChannel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<iTunesList>
<iTunes>
<Categories>
<Category category="Allegro" />
<Category category="Prestissimo" />
</Categories>
</iTunes>
</iTunesList>
</RssChannel>
I tried to create a method in a ApiController that looks like this:
public DemoList<Demo> GetAll()
{
var result = new DemoList<Demo>() { new Demo(){Y=2}, new Demo(), new Demo(){Y=1} };
result.Name = "Test";
return result;
}
Demo and DemoList look like this:
public interface INamedEnumerable<out T> : IEnumerable<T>
{
string Name { get; set; }
}
public class Demo
{
public int X { get { return 3; } }
public int Y { get; set; }
}
public class DemoList<T> : List<T>, INamedEnumerable<T>
{
public DemoList()
{
}
public string Name { get; set; }
}
I then cheked the ouput with fiddler
GET http://localhost:8086/api/Demo
and got the following:
XML (Accept header set to application/xml)
<ArrayOfDemo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/XXX.WebAPI"><Demo><Y>2</Y></Demo><Demo><Y>0</Y></Demo><Demo><Y>1</Y></Demo></ArrayOfDemo>
JSON (Accept header set to application/json)
[{"X":3,"Y":2},{"X":3,"Y":0},{"X":3,"Y":1}]
My question is quite simple: Why is the X variable not serialized with the XML version (I thought that readonly properties were serialized) and more important, why in both cases is the Name property (which is writable) not serialized??
What are the alternatives to make this work like I expected?
Edit:
Please, note that I'm in a WebAPI context! By default, the XmlSerializer is automatically set to XmlMediaTypeFormatter and the JSONSerializer to JsonMediaTypeFormatter
This seems to be a bug... using the following workaround made the trick:
public class ListWrapper<T>
{
public ListWrapper(INamedEnumerable<T> list)
{
List = new List<T>(list);
Name = list.Name;
}
public List<T> List { get; set; }
public string Name { get; set; }
}
XML serializers only allows serialization of properties with "set" provided.
What are you using to serialize it? If you don't need attributes you could use DataContractSerializer as mentioned here. By default properties without a set are not serialized however using DataContractSerializer or implementing IXmlSerializable should do the trick for you.
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);
}
}
}
Let's suppose I have this object:
[Serializable]
public class MyClass
{
public int Age { get; set; }
public int MyClassB { get; set; }
}
[Serializable]
public class MyClassB
{
public int RandomNumber { get; set; }
}
The XmlSerializer will serialize the object like that:
<MyClass>
<Age>0</age>
<MyClassB>
<RandomNumber>4234</RandomNumber>
</MyClassB>
</MyClass>
How can I made the property Age nullable? IE: to not serialize the property Age when it's under 0?
I tried with the Nullable, but it serialize my object like that:
<MyClass>
<Age d5p1:nil="true" />
<MyClassB>
<RandomNumber>4234</RandomNumber>
</MyClassB>
</MyClass>
By reading the MSDN documentation I found this:
You cannot apply the IsNullable property to a member typed as a value type because a value type cannot contain nullNothingnullptra null reference (Nothing in Visual Basic). Additionally, you cannot set this property to false for nullable value types. When such types are nullNothingnullptra null reference (Nothing in Visual Basic), they will be serialized by setting xsi:nil to true.
source: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable.aspx
I understand a value type can't be set to null. A valuetype is always set to something. The serialization can't make the decision to serialize it or not based on it's current value.
I tried with the attributes, but it didn't work out. I tried creating an agecontainer object and manipulate it's serialization with attributes, but it didn't work out.
What I really want is:
<MyClass>
<MyClassB>
<RandomNumber>4234</RandomNumber>
</MyClassB>
</MyClass>
When the property Age is below 0 (zero).
Looks like you'll have to implement custom serialization.
Yeah, that's what I though too, but I'd like to get away without it.
In the application, the object is much more complex, and I would like to not handle the serialization myself.
I just discovered this. XmlSerialier looks for a XXXSpecified boolean property to determine if it should be included. This should solve the problem nicely.
[Serializable]
public class MyClass
{
public int Age { get; set; }
[XmlIgnore]
public bool AgeSpecified { get { return Age >= 0; } }
public int MyClassB { get; set; }
}
[Serializable]
public class MyClassB
{
public int RandomNumber { get; set; }
}
Proof:
static string Serialize<T>(T obj)
{
var serializer = new XmlSerializer(typeof(T));
var builder = new StringBuilder();
using (var writer = new StringWriter(builder))
{
serializer.Serialize(writer, obj);
return builder.ToString();
}
}
static void Main(string[] args)
{
var withoutAge = new MyClass() { Age = -1 };
var withAge = new MyClass() { Age = 20 };
Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass>
Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass>
}
Edit: Yes, it is a documented feature. See the MSDN entry for XmlSerializer
Another option is to use a special pattern to create a Boolean field recognized by the XmlSerializer, and to apply the XmlIgnoreAttribute to the field. The pattern is created in the form of propertyNameSpecified. For example, if there is a field named "MyFirstName" you would also create a field named "MyFirstNameSpecified" that instructs the XmlSerializer whether to generate the XML element named "MyFirstName".
Extending Samuel's answer and Greg Beech's comment to the case of a boolean property: if the property is of type bool then you can't write a simple test in the propertySpecified property.
A solution is to use a Nullable<bool> type, then the test in the propertySpecified property is simply property.HasValue. e.g.
using System.Xml.Serialization;
public class Person
{
public bool? Employed { get; set; }
[XmlIgnore]
public bool EmployedSpecified { get { return Employed.HasValue; } }
}
An alternative to using a nullable type for a numeric property (suggested by Greg Beech) is to set the value property to an invalid default value, such as -1, as follows:
using System.ComponentModel;
using System.Xml.Serialization;
public class Person
{
[DefaultValue(-1)]
public int Age { get; set; }
[XmlIgnore]
public bool AgeSpecified { get { return Age >= 0; } }
}
You can use XmlElementAttribute.IsNullable:
[Serializable]
public class MyClass
{
[XmlElement(IsNullable = true)]
public int? Age { get; set; }
public int MyClassB { get; set; }
}
This should help
Make Age int? and..
public bool ShouldSerializeAge() { return Age.HasValue; }
..it does mean adding the ShouldSerializeXXX methods to your class!
You need to do custom XML serialization; see IXmlSerializer.
public class MyClass : IXmlSerializable
{
public int Age { get; set; }
public MyClassB MyClassB { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
// http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
return null;
}
public void ReadXml(XmlReader reader)
{
if (reader.IsStartElement("Age"))
Age = reader.ReadContentAsInt();
var serializer = new XmlSerializer(typeof(MyClassB));
MyClassB = (MyClassB)serializer.Deserialize(reader);
}
public void WriteXml(XmlWriter writer)
{
if (Age > 0)
{
writer.WriteStartElement("Age");
writer.WriteValue(Age);
writer.WriteEndElement();
}
var serializer = new XmlSerializer(typeof(MyClassB));
serializer.Serialize(writer, MyClassB);
}
}
Forget about Nullable ... ShouldSerializeXXX is a pretty solution.
Here Age will be serialized upon your condition.
[Serializable]
public class MyClass
{
public int Age { get; set; }
public int MyClassB { get; set; }
#region Conditional Serialization
public bool ShouldSerializeAge() { return age > 0; }
#endregion
}
[Serializable]
public class MyClassB
{
public int RandomNumber { get; set; }
}
xsd.exe will autogenerate the XXXSpecified property and accessors if you set the 'minoccurs' attribute as 'minoccurs="0"' for an element ... if you are using a schema to define your xml/class