3

I have a class that implements ICollection for convenience. When the class gets serialized to XML all the public properties are skipped and only the actual collection gets serialized. I read the following from the MSDN

Classes that implement ICollection or IEnumerable.

  • Only collections are serialized, not public properties.

Is there anyway to work around this? Is there a way to have a class that implements ICollection and still will output the public properties? Or do I have to use an XmlWriter and do it myself?

Just in case an example is needed.

public class Batch: ICollection<Foo>
{
    public string Bar { get; set; }
    
    public int Baz { get; set; }
    
    public List<Foo> Foos { get; private set; }
    
    public IEnumerator<Foo> GetEnumerator()
    {
        return Foos.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return Foos.GetEnumerator();
    }

    public void Add(Foo item)
    {
        Foos.Add(item);
    }

    public void Clear()
    {
        Foos.Clear();
    }

    public bool Contains(Foo item)
    {
        return Foos.Contains(item);
    }

    public void CopyTo(Foo[] array, int arrayIndex)
    {
        Foos.CopyTo(array, arrayIndex);
    }

    public bool Remove(Foo item)
    {
        return Foos.Remove(item);
    }

    public int Count { get { return Foos.Count; } }

    public bool IsReadOnly { get { return false; } }
}

The reason it is this way is that in another part of my code I am dealing with collections of things. IList IList etc. But for the batch there is information that applies to every Foo but that information is the same for every foo for one particular batch. Like perhaps a batch ID or Created DateTime. I wanted to be able to treat my batch and my other collections in the same way in some parts of my code because all i care about that is a collection and has a count. I don't care that some information is identical to every item in that collection.

The reason I wanted to do that was for serialization. I was trying to remove redundant information. If there is another way to structure my class that I do not lose that very important count then I am all ears. I was hoping to avoid creating another interface that just contains a count for a simple thing like this. It felt dirty but it might be the right thing.

Community
  • 1
  • 1
uriDium
  • 13,110
  • 20
  • 78
  • 138

2 Answers2

3

No, basically. This is not unique to XmlSerializer - large parts of the framework treat collections and elements as mutually exclusive. My suggestion: don't do that. Have something that is either a collection xor an element.

This does not mean the format has to change - you can usually encapsulate a list (rather than be a list) and use [XmlElement("someName")] to get the same type of output, for example:

public class PeopleWrapper
{
    [XmlAttribute("someValue")]
    public int SomeValue { get; set; }

    private readonly List<Person> people = new List<Person>();
    [XmlElement("person")]
    public List<Person> Items { get { return people; } }
}

then if another class had:

public PeopleWrapper People { get; set; }

you would get, in the xml:

<People someValue="123">
    <person>...</person>
    <person>...</person>
    <person>...</person>
</People>
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I have made some edits. Would that be similar to the way a SqlCommand has a SqlParameterCollection? – uriDium May 29 '13 at 10:14
  • @uriDium I guess... depends how far you want to take an analogy. But indeed, a `SqlCommand` *has* a collection of parameters as a property (`.Parameters`) - it is not *itself* a collection of parameters. Looking at your edit, `Batch` *has* a collection of `Foo` - called `.Foos`. Everything else (all the Add / Contains / GetEnumerator) is actually part of `Foos`, and doesn't belong on `Batch` IMO. If it was me, `Batch` would be just `.Foos`, `.Bar` and `.Baz`. – Marc Gravell May 29 '13 at 10:19
0

In that case you have to implement IXmlSerializable on your own. For more informations on this either take a look at MSDN and/or this SO answer.

Community
  • 1
  • 1
Oliver
  • 43,366
  • 8
  • 94
  • 151