I’ve been using Phil Haack‘s Custom Configuration Sections in 3 Easy Steps for some time now, and my configuration file management has never been happier… until I needed to read a collection of configuration elements.
Here’s a sample of the XML I needed to incorporate:
The typical solution is to write your own collection class (FilespecConfigurationElementCollection), inheriting from ConfigurationElementCollection, and ensuring your Filespec object inherits from ConfigurationElement. I figured there has to be a better way — and there is.
I wrote a generic version of ConfigurationElementCollection, which you can use to avoid writing the custom collection class. The code that follows is the generic class, the Filespec object I used, and the property declaration from my ConfigurationSettings class (as described in Phil’s previously mentioned article).
Note one key part of this implementation: You must override the ToString() method of your custom ConfigurationElement class to return a unique value. The generic ConfigurationElementCollection uses the ToString() method to obtain a unique key for each element in the collection.
// The ConfigurationElementCollection provides a simple generic implementation of ConfigurationElementCollection.
[ConfigurationCollection(typeof(ConfigurationElement))]
public class ConfigurationElementCollection : ConfigurationElementCollection where T : ConfigurationElement, new()
{
protected override ConfigurationElement CreateNewElement()
{
return new T();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((T)(element)).ToString();
}
public T this[int idx]
{
get { return (T)BaseGet(idx); }
}
}
// The Filespec class is an example of a custom configuration element.
// Note that we inherit from ConfigurationElement, and use ConfigurationProperty attributes.
public class Filespec : ConfigurationElement
{
public Filespec()
{
}
[ConfigurationProperty("path", DefaultValue="", IsKey=true, IsRequired=true)]
public string Path
{
get { return (string)(base["path"]); }
set { base["path"] = value; }
}
[ConfigurationProperty("type", IsKey=false, IsRequired = true)]
public FilespecType Type
{
get { return (FilespecType)(base["type"]); }
set { base["type"] = value; }
}
public override string ToString()
{
return this.Path;
}
}
// Finally, our ConfigurationSettings class (only part of the class is included).
// Note how we use the generic ConfigurationElementCollection.
public class ConfigurationSettings : ConfigurationSection
{
// ...
[ConfigurationProperty("filespecs", IsRequired=true)]
public ConfigurationElementCollection FileSpecs
{
get { return (ConfigurationElementCollection)this["filespecs"]; }
}
// ...
}
If you’re using a number of ConfigurationElementCollections, this is a great way to simplify your code.
Leave a comment