2

Repeating the ConfigurationPropertyAttribute name three times in the code really bothers me.
It so easy to miss a misspelling or copy/paste a property and forget to update one instance of the name.

Declaring a constant only solves one of these problems. Is there a better way?

I tried reflection, but enumerating the attributes seemed much more trouble, and uglier.

[ConfigurationProperty("port", DefaultValue = (int)0, IsRequired = false)]
[IntegerValidator(MinValue = 0, MaxValue = 8080, ExcludeRange = false)]
public int Port
{
    get
    {
        return (int)this["port"];
    }
    set
    {
        this["port"] = value;
    }
}

I know DRY is just a principle and often, in the real-world, principles must give way to pragmatism. But I'm sure someone has cleaner way?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
DanO
  • 2,526
  • 2
  • 32
  • 38

2 Answers2

3

You can use a non-declarative approach for configuration elements if you want. Examples can be found all over the internet - particularly at Unraveling the Mysteries of .NET 2.0 Configuration where the examples show both methods simultaneously.

class MyConfigurationElement : ConfigurationElement
{
    private static ConfigurationPropertyCollection _properties = new ConfigurationPropertyCollection();
    private static ConfigurationProperty _portProperty = new COnfigurationProperty("port", ..... ); // Will leave as example for you to add validator etc.

    static MyConfigurationElement()
    {
         _properties.Add(_portProperty);
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get { return _properties; }
    }

    public int Port  
    {
        get
        {
            return (int)this[_portProperty];
        }
        set
        {
           this[_portProperty] = value;
        }
    }    
}
Reddog
  • 15,219
  • 3
  • 51
  • 63
  • +1: I always neglect that way of doing it ;-) This also has the benefit of said as being faster (during runtime) then the declarative way (which is the reason why they used it for the WCF/System.ServiceModel configuration which is _extensive_ - sorry, can't remember the source where I read that). Arguably, that has the issue of one "forgetting" to actually add/remove a ConfigurationProperty to the collection, but only providing a get/set-property in code. Well, I guess with either approach, in the end you have to know what you are doing and employ proper "craftsmanship". – Christian.K May 04 '12 at 04:04
2

Why does using a constant not solve all three problems?

Example:

class MyConfigurationElement : ConfigurationElement
{

    // Use public, private or internal, as you see fit.
    private const string PortName = "port";

    // Add something like this, if you also want to access the string value
    // and don't want to recompile dependend assemblies when changing the
    // string 'port' to something else.
    // public static readonly PortNameProperty = PortName;

    [ConfigurationProperty(PortName, DefaultValue = (int)0, IsRequired = false)]
    [IntegerValidator(MinValue = 0, MaxValue = 8080, ExcludeRange = false)] 
    public int Port  
    {
        get
        {
            return (int)this[PortName];
        }
        set
        {
           this[PortName] = value;
        }
    }    
}

Side Note: If you might also consider using the Configuration Section Designer. Frankly, I have only tested it a couple of years ago and never used it since then, but maybe it also solves your concerns about DRY.

Christian.K
  • 47,778
  • 10
  • 99
  • 143
  • 1
    I think in the sense of copy/paste/edit errors. You copy your Port property to make a Foo property. You change the attribute declaration from PortName to FooName, but forget to change the get/set references, and it compiles fine. A solution that solves all the problems allows specifiying the name once and only once rather than repeated three times. But using constants is still an improvement over repeated magic strings. – hatchet - done with SOverflow May 03 '12 at 19:28
  • 1
    @hatchet agreed. However I think we should not over complicate things here. A little care and good testing catch such issues easily. Also, there still remains the issue of XSD files, which you should create (for proper intellisense support when editing app.config files) anyway. In there you have the (attribute) name again. Short of code/XSD generation from a single source, there is nothing that can help here. – Christian.K May 04 '12 at 03:53