【问题标题】:.NET custom configuration - Can I have elements collection with non-homogeneous elements?.NET 自定义配置 - 我可以使用非同质元素收集元素吗?
【发布时间】:2012-01-03 14:00:03
【问题描述】:

我在 app/web.config 中注册了一个自定义配置部分,我们称之为MySection。我在该部分中有一个ElementCollection 元素,称为MyElements。在元素集合中,我希望拥有由不同类表示的元素 - 想法是这些是具有一些共同属性和一些特定于实例的相似类。

这里是一些xml配置示例:

<MySection>
  <MyElements>
    <Element1 name="someProp1" value="someValue" />
    <Element2 name="someProp2" format="{0}{1}" />
  </MyElements>
</MySection>

在我的简单示例中,所有元素都必须具有“名称”属性,有些还必须具有“值”属性,而另一些则具有“格式”属性。 在这里,我希望 Element1Element2 在 .NET 运行时中由两个不同的类表示,它们具有定义“名称”属性的公共基类。

就我对 .NET 配置的深入研究而言,我的印象是元素集合(如此处的“MyElements”)应该包含同质元素(仅一种类型)。那么,是否有可能实现我想要的 - 让它包含不同类的元素。这个想法是避免为不同的元素类型拥有多个元素集合,而不是为每个自定义 ConfigurationElement 实现编写所有重复属性。

【问题讨论】:

    标签: c# configuration


    【解决方案1】:

    您可以通过覆盖 ElementCollection 类中的 OnDeserializeUnrecognizedElement 方法并通过打开 ex 的标记名称来创建 Element1 和 Element2 的表示来实现此目的。但是 AFAIR 子元素无论如何都应该从共同祖先派生,否则这样做太麻烦了。

    将集合定义为:

    public class MyElementCollection : ConfigurationElementCollection
    {
        const string ELEMENT1 = "Element1";
        const string ELEMENT2 = "Element2";
    
        protected override ConfigurationElement CreateNewElement ()
        {
            return new MyElement (this);
        }
    
        protected override object GetElementKey (ConfigurationElement element)
        {
            return ((MyElement)element).Key;
        }
    
        // This method called when framework sees unknown element tag
        // inside the collection. You can choose to handle it yourself
        // and return true, or return false to invoke default action
        // (exception will be thrown).
        protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
        {
            if (elementName == ELEMENT1 || elementName == ELEMENT2 {
                var myElement = new MyElement (this);
    
                switch (elementName) {
                case ELEMENT1:
                    myElement.Type = MyElementType.Element1;
                    break;
                case ELEMENT2:
                    myElement.Type = MyElementType.Element2;
                    break;
                }
    
                myElement.DeserializeElementForConfig (reader, false);
                BaseAdd (myElement);
    
                return true;
            }
    
            return false;
        }
    }
    

    和子元素:

    public enum MyElementType
    {
        Element1,
        Element2,
    }
    
    public class MyElement : ConfigurationElement
    {
        const string NAME = "name";
        const string VALUE = "value";
        const string FORMAT = "format";
    
        // keys should be unique, current collection count will do
        // the trick without introducing artificial keys
        public MyElement (ConfigurationElementCollection collection)
        {
            Key = collection.Count;
        }
    
        // note that this is not ConfigurationProperty
        public int Key { get; private set; }
    
        // note that this is not ConfigurationProperty
        public MyElementType Type { get; set; }
    
        [ConfigurationProperty(NAME)]
        public string Name {
            get { return (string)this [NAME]; }
        }
    
        [ConfigurationProperty(VALUE)]
        public string Value {
            get { return (string)this [VALUE]; }
        }
    
        [ConfigurationProperty(FORMAT)]
        public string Format {
            get { return (string)this [FORMAT]; }
        }
    
        // This is called when framework needs a copy of the element,
        // but it knows only about properties tagged with ConfigurationProperty.
        // We override this to copy our Key and Type, otherwise they will
        // have default values.
        protected override void Reset (ConfigurationElement parentElement)
        {
            base.Reset (parentElement);
    
            var myElement = (MyElement)parentElement;
            Key = myElement.Key;
            Type = myElement.Type;
        }
    
        // original ConfigurationElement have this protected,
        // redeclaring as protected internal to call it from collection class
        protected internal void DeserializeElementForConfig (XmlReader reader, bool serializeCollectionKey)
        {
            DeserializeElement (reader, serializeCollectionKey);
        }
    }
    

    【讨论】:

    • 感谢您的回答。事实上,一个共同的祖先是我无论如何都要使用的。至少,我正在尝试重用相似元素的共同属性,因此共同祖先可以存储它们并减少具体元素的代码:)
    猜你喜欢
    • 2021-05-14
    • 2018-10-01
    • 2015-12-04
    • 2011-06-05
    • 2017-07-08
    • 2011-04-03
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    相关资源
    最近更新 更多