【问题标题】:Get ConfigurationElement parent in app.config在 app.config 中获取 ConfigurationElement 父级
【发布时间】:2025-12-20 05:05:07
【问题描述】:

我为我的 app.config 创建了一个自定义的 ConfigurationSectionConfigurationElement(s)ConfigurationElementCollection(s),它基于 this documentation

现在我希望能够访问任何配置元素中的父元素。
例如以下几行:

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 getter 中分配该属性值。

【问题讨论】:

  • “ChildElement”类不是“NestedChildElement”类的父类。
  • 请注意,“ChildElement”包含“ConfigurationProperty”或“NestedChildElement”。在“app.config”中,这是一个“嵌套子”XML 元素,它是“子”XML 元素的父元素。我希望这能说明问题。

标签: c# app-config configurationsection configurationelement


【解决方案1】:

您没有错过ConfigurationElement 中的任何内容,它无法为您提供任何层次结构或顺序信息。您必须自己保留这些信息,例如查看this answer

对于通用解决方案,您可能需要查看 my POC 以在 app.config 中定义父占位符。
附带说明一下,在以前的版本中,我使用接口(您可以检查以前的提交)和在当前版本中使用扩展属性来完成此操作。

此外,以下是满足您要求的精简版本:

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

【讨论】: