views:

69

answers:

2

Hello, everyone,

This is my first question on Stack Overflow. Apologies in advance if I don't do things quite right while I'm learning how things work here.

Here is my code :

public void TestSerialize()
{
    ShoppingBag _shoppingBag = new ShoppingBag();
    Fruits _fruits = new Fruits();
    _fruits.testAttribute = "foo";

    Fruit[] fruit = new Fruit[2];
    fruit[0] = new Fruit("pineapple");
    fruit[1]= new Fruit("kiwi");

    _fruits.AddRange(fruit);

    _shoppingBag.Items = _fruits;

    Serialize<ShoppingBag>(_shoppingBag, @"C:\temp\shopping.xml");
}

public static void Serialize<T>(T objectToSerialize, string filePath) where T : class
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));

    using (StreamWriter writer = new StreamWriter(filePath))
    {
        serializer.Serialize(writer, objectToSerialize);
    }
}

[Serializable]
public class ShoppingBag
{
    private Fruits _items;

    public Fruits Items
    {
        get { return _items; }
        set {_items = value; }
    }
}

public class Fruits : List<Fruit>
{
    public string testAttribute { get; set; }
}

[Serializable]
public class Fruit 
{
    public Fruit() { }

    public Fruit(string value)
    {
        Name = value;
    }

    [XmlAttribute("name")]
    public string Name { get; set; }
}

It produces this XML :

<?xml version="1.0" encoding="utf-8" ?> 
<ShoppingBag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <Items>
    <Fruit name="pineapple" /> 
    <Fruit name="kiwi" /> 
  </Items>
</ShoppingBag>

I don't understand why I am not getting <Items testAttribute="foo">

Please can anyone tell me what I need to add to my code so that the Serializer will write this attribute out?

Thanks,

+2  A: 

You need an intermediary class there:

class Program
{
    static void Main()
    {
        var shoppingBag = new ShoppingBag
        {
            Items = new ShoppingBagItems
            {
                Fruits = new List<Fruit>(new[] {
                    new Fruit { Name = "pineapple" },
                    new Fruit { Name = "kiwi" },
                }),
                TestAttribute = "foo"
            }
        };
        var serializer = new XmlSerializer(typeof(ShoppingBag));
        serializer.Serialize(Console.Out, shoppingBag);
    }
}

public class ShoppingBag
{
    public ShoppingBagItems Items { get; set; }
}

public class ShoppingBagItems
{
    [XmlElement("Fruit")]
    public List<Fruit> Fruits { get; set; }

    [XmlAttribute("testAttribute")]
    public string TestAttribute { get; set; }
}

public class Fruit
{
    [XmlAttribute("name")]
    public string Name { get; set; }
}

Also note that you don't need to decorate your classes with the [Serializable] attribute as it is used only for binary serialization. Another remark is that you don't need to derive from List<T>, simply use it as a property.

Darin Dimitrov
Thanks for your answer, Darin.I do not understand what you mean when you say that I need an intermediary class. You have used 3 classes (ShoppingBag, ShoppingBagItems, Fruit) as I did (ShoppingBag, Fruits, Fruit).Thanks for the tip about not needing the `[Serializable]` attribute.Your point about `List<T>` is the crux of my problem. If I change my original code so as not to derive `Fruits` from `List<T>`, then it works fine ...
However, back at work I have been requested to derive from List<T> so that when I deserialize the XML I can easily use foreach on my classes (without having to implement IEnumerable myself). (My XML has 7 levels of objects; I am not performing the Serialization, just the Deserialization. What started this was that I was not able to read an attribute at level 4 and so I thought if I could serialize it correctly then I should be able to deserialize it). So, why does deriving from `List<T>` stop the attribute being written? and how can I both derive from List<T> and write/read that attribute?
A: 

Unfortunately, when serializing a collection the XmlSerializer doesn't take into account the extra properties of that collection. It only considers the members that implement ICollection<T>. If you want to serialize extra attributes, you need to wrap the collection in another class that is not a collection itself.

Thomas Levesque