how to have custom attribute in ConfigurationElementCollection?

后端 未结 4 690
深忆病人
深忆病人 2020-12-23 18:34

for configuration as following


  
  ... other entries


        
相关标签:
4条回答
  • 2020-12-23 18:55

    This may be a bit late but may be helpful to others.

    It is possible but with some modification.

    • ConfigurationElementCollection inherits ConfigurationElement as such "this[string]" is available in ConfigurationElement.

    • Usually when ConfigurationElementCollection is inherited and implemented in another class, the "this[string]" is hidden with "new this[string]".

    • One way to get around it is to create another implementation of this[] such as "this[string, string]"

    See example below.

    public class CustomCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new CustomElement();
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((CustomElement)element).Name;
        }
    
        public CustomElement this[int index]
        {
            get { return (CustomElement)base.BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                    BaseRemoveAt(index);
    
                BaseAdd(index, value);
            }
        }
    
        // ConfigurationElement this[string] now becomes hidden in child class
        public new CustomElement this[string name]
        {
            get { return (CustomElement)BaseGet(name); }
        }
    
        // ConfigurationElement this[string] is now exposed
        // however, a value must be entered in second argument for property to be access
        // otherwise "this[string]" will be called and a CustomElement returned instead
        public object this[string name, string str = null]
        {
            get { return base[name]; }
            set { base[name] = value; }
        }
    }
    
    0 讨论(0)
  • 2020-12-23 19:01

    If you want to genericize it, this should help:

    using System.Configuration;
    
    namespace Abcd
    {
      // Generic implementation of ConfigurationElementCollection.
      [ConfigurationCollection(typeof(ConfigurationElement))]
      public class ConfigurationElementCollection<T> : ConfigurationElementCollection
                                             where T : ConfigurationElement, IConfigurationElement, new()
      {
        protected override ConfigurationElement CreateNewElement()
        {
          return new T();
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
          return ((IConfigurationElement)element).GetElementKey();
        }
    
        public T this[int index]
        {
          get { return (T)BaseGet(index); }
        }
    
        public T GetElement(object key)
        {
          return (T)BaseGet(key);
        }
      }
    }
    

    Here's the interface referenced above:

    namespace Abcd
    {
      public interface IConfigurationElement
      {
        object GetElementKey();
      }
    }
    
    0 讨论(0)
  • 2020-12-23 19:17

    Let's suppose you have this .config file:

    <configuration>
        <configSections>
            <section name="mySection" type="ConsoleApplication1.MySection, ConsoleApplication1" /> // update type  & assembly names accordingly
        </configSections>
    
        <mySection>
            <MyCollection default="one">
                <entry name="one" />
                <entry name="two" />
            </MyCollection>
        </mySection>
    </configuration>
    

    Then, with this code:

    public class MySection : ConfigurationSection
    {
        [ConfigurationProperty("MyCollection", Options = ConfigurationPropertyOptions.IsRequired)]
        public MyCollection MyCollection
        {
            get
            {
                return (MyCollection)this["MyCollection"];
            }
        }
    }
    
    [ConfigurationCollection(typeof(EntryElement), AddItemName = "entry", CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class MyCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new EntryElement();
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
            if (element == null)
                throw new ArgumentNullException("element");
    
            return ((EntryElement)element).Name;
        }
    
        [ConfigurationProperty("default", IsRequired = false)]
        public string Default
        {
            get
            {
                return (string)base["default"];
            }
        }
    }
    
    public class EntryElement : ConfigurationElement
    {
        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get
            {
                return (string)base["name"];
            }
        }
    }
    

    you can read the configuration with the 'default' attribute, like this:

        MySection section = (MySection)ConfigurationManager.GetSection("mySection");
        Console.WriteLine(section.MyCollection.Default);
    

    This will output "one"

    0 讨论(0)
  • 2020-12-23 19:17

    I don't know if it's possible to have a default value in a ConfigurationElementCollection. (it doesn't seen to have any property for default value).

    I guess you have to implement this by yourself. Look at the example below.

    public class Repository : ConfigurationElement
    {
        [ConfigurationProperty("key", IsRequired = true)]
        public string Key
        {
            get { return (string)this["key"]; }
        }
    
        [ConfigurationProperty("value", IsRequired = true)]
        public string Value
        {
            get { return (string)this["value"]; }
        }
    }
    
    public class RepositoryCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new Repository();
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
            return (element as Repository).Key;
        }
    
        public Repository this[int index]
        {
            get { return base.BaseGet(index) as Repository; }
        }
    
        public new Repository this[string key]
        {
            get { return base.BaseGet(key) as Repository; }
        }
    
    }
    
    public class MyConfig : ConfigurationSection
    {
        [ConfigurationProperty("currentRepository", IsRequired = true)]
        private string InternalCurrentRepository
        {
            get { return (string)this["currentRepository"]; }
        }
    
        [ConfigurationProperty("repositories", IsRequired = true)]
        private RepositoryCollection InternalRepositories
        {
            get { return this["repositories"] as RepositoryCollection; }
        }
    }
    

    Here's the XML config:

      <myConfig currentRepository="SQL2008">
        <repositories>
          <add key="SQL2008" value="abc"/>
          <add key="Oracle" value="xyz"/>
        </repositories>
      </myConfig>
    

    And then, at your code, you access the default item using the following:

    MyConfig conf = (MyConfig)ConfigurationManager.GetSection("myConfig");
    string myValue = conf.Repositories[conf.CurrentRepository].Value;
    

    Of course, the MyConfig class can hide the details of accessing the Repositories and CurrentRepository properties. You can have a property called DefaultRepository (of type Repository) in MyConfig class to return this.

    0 讨论(0)
提交回复
热议问题