I have a Dictionary containing configuration values for other classes (tasks which will be executed periodically performing assorted specialized logic) which are persisted in a database and then passed back in at execution time.
I want to create a strongly typed wrapper for this Dictionary, both to allow easy access to the values and to cast them to the proper type.
At the moment I have something like this:
public class ConfigurationWrapper {
Dictionary<string, string> _configuration;
public ConfigurationWrapper(Dictionary<string, string> configuration) {
_configuration = configuration;
InitializeDefaultValues();
}
public virtual GetConfigurationCopy() {
return new Dictionary(_configuration);
}
protected InitializeDefaultValues() {
Type t = GetType();
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(t);
foreach (PropertyDescriptor property in properties) {
AttributeCollection attributes = property.Attributes;
DefaultValueAttribute defaultValue = (DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
if (defaultValue != null) {
if (!Configuration.ContainsKey(property.Name)) {
Configuration[property.Name] = Convert.ToString(defaultValue.Value, CultureInfo.InvariantCulture);
}
}
}
}
}
public class MyTaskConfigurationWrapper : ConfigurationWrapper {
private const string MyIntPropertyKey = "MyIntProperty";
[DefaultValue(7)]
int MyIntProperty {
get { return Convert.ToInt32(_configuration[MyIntPropertyKey], CultureInfo.InvarientCulture); }
set { _configuration[MyIntPropertyKey] = value.ToString(CultureInfo.InvarientCulture); }
}
// More properties of various types.
}
My question is if there's a way to improve this design.
One thing I've considered is using reflection to get the name for the property (and hence the configuration value) as discussed here. This saves having to create a string key and implicitly forces the key to have the same name as the property (which is required for the InitializeDefaultValues()
code to function), but it also obscures the fact that this is the case and that that the name of the configuration value will change if the name of the property is changed. So it's a trade off.
This would look something like the following:
// Could alternately use PropertyHelper example with some compile time checking
protected string GetProperty(MethodBase getMethod) {
if (!getMethod.Name.StartsWith("get_") {
throw new ArgumentException(
"GetProperty must be called from a property");
}
return _configuration[getMethod.Name.Substring(4)];
}
protected string SetProperty(MethodBase getMethod, string value) {
// Similar to above except set instead of get
}
[DefaultValue(7)]
int MyIntProperty {
get { return Convert.ToInt32(GetProperty(MethodInfo.GetCurrentMethod(), CultureInfo.InvarientCulture); }
set { SetProperty(MethodInfo.GetCurrentMethod(), value.ToString(CultureInfo.InvarientCulture); }
}