I\'m tracing legacy code in my project written in C#.
I find the following code:
public class FooCollection : Collection {};
I don't understand why (and when) we need to create our own Collection class like this.
One of the main use cases for implementing a custom Collection<T>
is serialization.
If you want to customize how the collection is serialized (for example to XML, using XmlSerializable), you can create a custom collection class and implement IXmlSerializable
on it. Then, you can change how to read or write the collection by manipulating the Read
and Write
methods of that interface.
class MyCollection : Collection<string>, IXmlSerializable
{
public XmlSchema GetSchema()
{
return(null);
}
public void WriteXml(XmlWriter writer)
{
//// foreach (var item in Items)
//// writer.Write...
}
public void ReadXml(XmlReader reader)
{
//// Items.Add(reader.Read...
}
}
This is in most cases preferable compared to implementing IXmlSerializable
on the parent class, as it leads to less code overall and promotes reuse (you can reuse the same collection in multiple places and it will be serialized in the same way as long as you use a XmlSerializer
to serialize it).
I've used this recently due to a requirement from an external system that needed each element of the collection to generate a XML node with the index of the element appended to it.
The final structure looked somewhat like this:
<MyCollection>
<Item1>first item</Item1>
<Item2>second item</Item2>
...
</MyCollection>
I'm not fond of coupling the collection to the serialization like this, but sometimes it is a valid approach.
I don't understand why (and when) we need to create our own Collection class like this.
I never would. I personally find the Collection
class to not be useful at all. I have not yet found a use for it.
One of the main problems with the type is that most of the method aren't virtual. The only virtual methods that are ClearItems
, InsertItem
, RemoveItem
, and SetItem
(along with Equals
, GetHashCode
, and ToString
from Object
). The rest of the methods/properties aren't virtual, and so cannot be overridden. This means you can alter the semantics for adding/inserting/removing an item slightly, but that's all.
What's the data structure used in
Collection<T>
?
Internally it is backed by a List<T>
.
Why not just use the build-in collection (
array
,List<T>
,Dictionary<K,V>
, ...)
In virtually all instances you would. While there are occasional instances in which you might actually want to create a brand new collection type, I've never found a use in which Collection<T>
was helpful in creating such a custom collection. Generally it's just best to implement some of the interfaces in the Collections
namespace, based on what your collection can fulfill, and optionally compose the type using other collections as instance fields, if it is merely an extension of an existing collection.
I don't understand why (and when) we need to create our own Collection class like this.
You don't really "need" to; you could just use Collection<IFoo>
directly, but having a specific class can help readability.
Also, it allows you to add specific behavior for this collection type as the Collection<T>
class allows most operations to be redefined by overriding virtual methods; this allows you to customize the behavior of the standard collection methods.
So, for example, while you cannot directly override the Add
method, you can override InsertItem
which is then used by Add
, AddRange
etc.
Why not just use the build-in collection (array, List, Dictionary, ...)
An array has a fixed length, so you can't add or remove items; so it's not really equivalent. Dictionary<K,V>
associates a value with a key, so it has a clearly different purpose. List<T>
could be used instead, as long as you don't need to customize the behavior; this class is not designed for inheritance, since its methods are non-virtual.
What's the data structure used in Collection ?? array? or linked list?
Collection<T>
acts as a wrapper around another IList<T>
. By default, it uses a List<T>
(which is based on an array), but you can pass any other IList<T>
implementation to the constructor, and it will use that instead.
By stating that you are inheriting the Collection<T>
class, you declare that your class IS-A
Collection<T>
, meaning that you have all it's API implemented (either by the derived class or by base the Collection<T>
class).
The advantage in the inheritance is that you can decide to override some of the methods and handle them in a way you find more suitable to your needs or to the type T
(IFoo
in your case).
In the same manner you can also decide to extend your API in order to support some other functionality that you find appropriate for your situation.
For example if you class IFoo
looks some thing like this:
public interface IFoo
{
int a;
int b;
}
In your derived class you can add an overload to the Remove that will look something like:
public bool Remove(int a, int b )...
And it will remove all occurrences of items that has certain values for a
and b