I first read the MSDN
example on custom configuration collections and saw what was involved in
creating a custom collection from the example. Maybe there is an easier way,
but that is where generics and inheritance come into play. Instead of
implementing that approach every time, I created this element class:
Listing 4
namespace Nucleo.Configuration
{
public abstract class ConfigurationElementBase:
System.Configuration.ConfigurationElement
{
protected internal abstract string Key
{
get;
}
}
}
The key property is something that must be overridden and
returns a unique value that identifies an element in a collection. The key is important
because the base collection for configuration collections uses a unique value.
The key property ensures this. Because the collection knows of the Key
property in the element base interface, the collection can automatically use
the element without having to create a custom collection on your own. The
following class is the base collection class, which defines a generic property
that references the element base class above.
Listing 5
namespace Nucleo.Configuration
{
public abstract class ConfigurationCollectionBase < T > :
ConfigurationElementCollection where T: ConfigurationElementBase
{
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.AddRemoveClearMap;
}
}
public T this[int index]
{
get
{
return (T)this.BaseGet(index);
}
set
{
if (this.BaseGet(index) != null)
this.BaseRemoveAt(index);
this.BaseAdd(index, value);
}
}
new public T this[string key]
{
get
{
return (T)this.BaseGet(key);
}
}
public void Add(T element)
{
this.BaseAdd(element);
}
public void Clear()
{
this.BaseClear();
}
public bool Contains(string key)
{
return (this.BaseGet(key) != null);
}
protected override ConfigurationElement CreateNewElement()
{
return Activator.CreateInstance < T > ();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((T)element).Key;
}
public void Remove(T element)
{
this.Remove(element.Key);
}
public void Remove(string key)
{
this.BaseRemove(key);
}
public void RemoveAt(int index)
{
this.BaseRemoveAt(index);
}
}
}
Now, because the work is done in the base collections class,
inheritance from this is a snap and reduces the amount of code needed. For
instance, below is a derived implementation of the element.
Listing 6
namespace Nucleo.Web.Configuration
{
public class IndividualPageElement: ConfigurationElementBase
{
protected override string Key
{
get
{
return this.PageName;
}
}
}
}
The collection definition is even easier.
Listing 7
public class IndividualPageElementCollection :
ConfigurationCollectionBase<IndividualPageElement>
{
}
That is all it takes to implement a collection with all that
functionality and with strong typing. This is a more useful example because it
really can cut down on the total amount of coding that is required for a
collection. However, this usage is not limited to collections, but can be used
in many scenarios.