Получить родительский элемент ConfigurationElement в app.config

Я создал кастом ConfigurationSection, ConfigurationElement(s) а также ConfigurationElementCollection(s) для моего app.config он основан на этой документации.

Теперь я хотел бы иметь доступ к родительскому элементу в любом элементе конфигурации.
Например, что-то в строках следующего:

public class CustomSection : ConfigurationSection
{
    [ConfigurationProperty("child")]
    public ChildElement Child
    {
        get { return (ChildElement)this["child"]; }
        set { this["child"] = value; }
    }
}

public class ChildElement : ConfigurationElement
{
    [ConfigurationProperty("name")]
    public string Name
    {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    [ConfigurationProperty("nestedchild")]
    public NestedChildElement NestedChild
    {
        get { return (NestedChildElement)this["nestedchild"]; }
        set { this["nestedchild"] = value; }
    }
}

public class NestedChildElement : ConfigurationElement
{
    [ConfigurationProperty("name")]
    public string Name
    {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    public void Sample()
    {
        // How can I access parent ChildElement object
        // and also its parent CustomSection object from here?
    }
}

Есть ли что-то в базе ConfigurationElement класс, который я пропускаю и который позволил бы мне сделать это?

Я надеюсь, возможно ли достичь этого с помощью какого-то общего решения;
Тот, который не потребует ввести что-то вроде Parent свойство каждого элемента, а затем необходимо назначить это значение свойства в каждом ConfigurationProperty добытчик.

1 ответ

Решение

Вы ничего не пропустили в ConfigurationElement, он не может дать вам никакой иерархии или информации о заказе. Вы должны будете сохранить эту информацию самостоятельно, например, посмотрите этот ответ.

Для общего решения вы можете проверить мой POC для определения родительских заполнителей в app.config.
Как примечание, в предыдущей версии я сделал это с интерфейсом (вы могли проверить предыдущие коммиты) и в текущей версии со свойством extension.

Кроме того, ниже приведена урезанная версия, которая удовлетворяет только вашим требованиям:

public abstract class ConfigurationElementBase : ConfigurationElement
{
    protected T GetElement<T>(string name) where T : ConfigurationElement
        => this.GetChild<T>(name);
}

public abstract class ConfigurationSectionBase : ConfigurationSection
{
    protected T GetElement<T>(string name) where T : ConfigurationElement
        => this.GetChild<T>(name);
}

public static class ConfigurationExtensions
{
    private static readonly Dictionary<ConfigurationElement, ConfigurationElement> Parents =
        new Dictionary<ConfigurationElement, ConfigurationElement>();

    public static T GetParent<T>(this ConfigurationElement element) where T : ConfigurationElement
        => (T)Parents[element];

    private static void SetParent(this ConfigurationElement element, ConfigurationElement parent)
        => Parents.Add(element, parent);

    private static object GetValue(this ConfigurationElement element, string name)
        => element.ElementInformation.Properties.Cast<PropertyInformation>().First(p => p.Name == name).Value;

    internal static T GetChild<T>(this ConfigurationElement element, string name) where T : ConfigurationElement
    {
        T childElement = (T)element.GetValue(name);
        if (!Parents.ContainsKey(childElement))
            childElement.SetParent(element);
        return childElement;
    }
}

Теперь вы можете использовать эти базовые классы конфигурации в своем пользовательском разделе следующим образом:

public class CustomSection : ConfigurationSectionBase
{
    [ConfigurationProperty("name")]
    public string Name
    {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    [ConfigurationProperty("child")]
    public ChildElement Child => base.GetElement<ChildElement>("child");
}

public class ChildElement : ConfigurationElementBase
{
    [ConfigurationProperty("name")]
    public string Name
    {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    [ConfigurationProperty("nestedchild")]
    public NestedChildElement NestedChild => base.GetElement<NestedChildElement>("nestedchild");
}

public class NestedChildElement : ConfigurationElement
{
    [ConfigurationProperty("name")]
    public string Name
    {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    public void Sample()
    {
        ChildElement parentChildElement = this.GetParent<ChildElement>();
        CustomSection parentCustomSection = parentChildElement.GetParent<CustomSection>();
        // TODO Use the parents ...
    }
Другие вопросы по тегам