как иметь пользовательский атрибут в ConfigurationElementCollection? - PullRequest
25 голосов
/ 12 января 2012

для конфигурации следующим образом

<MyCollection default="one">
  <entry name="one" ... other attrubutes />
  ... other entries
</MyCollection>

при реализации MyCollection, что я должен сделать для атрибута "default"?

Ответы [ 4 ]

54 голосов
/ 16 января 2012

Предположим, у вас есть этот файл .config:

<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>

Затем с помощью этого кода:

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"];
        }
    }
}

вы можете прочитать конфигурацию с атрибутом 'default', например так::

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

Это выведет "один"

5 голосов
/ 16 января 2012

Я не знаю, возможно ли иметь значение по умолчанию в ConfigurationElementCollection. (не было обнаружено никакого свойства для значения по умолчанию).

Полагаю, вы должны реализовать это самостоятельно. Посмотрите на пример ниже.

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; }
    }
}

Вот XML-конфигурация:

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

И затем, по вашему коду, вы получаете доступ к элементу по умолчанию, используя следующее:

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

Конечно, класс MyConfig может скрывать детали доступа к свойствам Repositories и CurrentRepository. У вас может быть свойство DefaultRepository (типа Repository) в классе MyConfig, чтобы возвращать это.

1 голос
/ 01 декабря 2013

Это может быть немного поздно, но может быть полезно для других.

Возможно, но с некоторыми изменениями.

  • ConfigurationElementCollection наследует ConfigurationElement, так как «this [string]» доступна в ConfigurationElement.

  • Обычно, когда ConfigurationElementCollection наследуется и реализуется в другом классе, «this [string]» скрывается с «new this [string]».

  • Один из способов обойти это - создать другую реализацию this [], такую ​​как "this [string, string]"

См. Пример ниже.

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 голосов
/ 20 января 2012

Если вы хотите обобщить это, это должно помочь:

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);
    }
  }
}

Вот интерфейс, указанный выше:

namespace Abcd
{
  public interface IConfigurationElement
  {
    object GetElementKey();
  }
}
...