【问题标题】:Polymorphic custom configuration section多态自定义配置部分
【发布时间】:2014-01-19 20:16:48
【问题描述】:

假设我有以下配置部分....

<yak>
    <whaa hello="world" />
</yak>
<yak>
   <whaa hello="world" blot="1" />
</yak>

因为第二个&lt;whaa&gt; 元素具有额外的属性,所以我想将它映射到映射到第一个&lt;whaa&gt; 元素的类型的子类型。

那么如何获得多态绑定呢?

【问题讨论】:

    标签: .net custom-configuration


    【解决方案1】:

    这是一种使用编程解决方案的方法,该解决方案覆盖ConfigurationSection 类的OnDeserializeUnrecognizedElement 方法。基本和子配置元素类:

    public class Whaa : ConfigurationElement
    {
        [ConfigurationProperty("hello", IsRequired = true)]
        public string Hello
        {
            get
            {
                return base["hello"] as string;
            }
            set
            {
                base["hello"] = value;
            }
        }
    }
    
    public class WhaaChild : Whaa
    {
        [ConfigurationProperty("blot", IsRequired = true)]
        public string Blot
        {
            get
            {
                return base["blot"] as string;
            }
            set
            {
                base["blot"] = value;
            }
        }
    }
    

    配置节类:

    public class Yak : ConfigurationSection
    {
        public Whaa MyProperty;
    
        protected override bool
            OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
        {
            if (elementName == "whaa")
            {
                try
                {
                    var hello = reader.GetAttribute("hello");
                    if (hello != null)
                    {
                        var blot = reader.GetAttribute("blot");
                        if (blot != null)
                        {
                            MyProperty = new WhaaChild()
                            {
                                Blot = blot,
                                Hello = hello
                            };
                        }
                        else
                        {
                            MyProperty = new Whaa()
                            {
                                Hello = hello
                            };
                        }
                    }
                }
                catch (Exception)
                {
                    // TODO: add exception handling
                }
            }
            return true;
        }
    }
    

    示例用法:

    var yakSectionSettings = (Yak)ConfigurationManager.GetSection("yak");
    

    以及配置标记:

    <configSections>
        <section name="yak" type="Yak, MyApplication"/>
    </configSections>
    

    您现在可以使用:

    <yak>
        <whaa hello="world"/>
    </yak>
    

    用于获取Whaa 对象,或者:

    <yak>
        <whaa hello="world" blot="1"/>
    </yak>
    

    用于在运行时获取WhaaChild 对象。

    【讨论】:

      【解决方案2】:

      This 解决方案使用代理类来包装子类型实现。底部有一条注释,甚至提到了为不同的子类型以不同的方式命名集合元素,因此大致如下:

      <yak>
          <whaa hello="world" />
      </yak>
      <yak>
         <whaaChild hello="world" blot="1" />
      </yak>
      

      在下面发布摘录以防万一有一天链接失效,但请先尝试链接来支持他们的博客!

      NestedConfiguration.cs

      using System;
      using System.Collections.Generic;
      using System.Configuration;
      using System.Text;
      using System.Xml;
      
      namespace NestedConfiguration
      {
        public class CollectionSection : ConfigurationSection
        {
          [ConfigurationProperty("collection", IsDefaultCollection = false)]
          [ConfigurationCollection(typeof(CollectionConfig), AddItemName = "add")]
          public CollectionConfig Collection
          {
            get
            {
              return (CollectionConfig) this["collection"];
            }
      
            set
            {
              this["collection"] = value;
            }
          }
        }
      
        public class Parent : ConfigurationElement
        {
          [ConfigurationProperty("name", IsRequired = true)]
          public string Name
          {
            get
            {
              return (string) this["name"];
            }
      
            set
            {
              this["name"] = value;
            }
          }
      
          [ConfigurationProperty("type", IsRequired = true)]
          public string Type
          {
            get
            {
              return (string) this["type"];
            }
      
            set
            {
              this["type"] = value;
            }
          }
      
          public void ProxyDeserializeElement(XmlReader reader, bool serializeCollectionKey)
          {
            DeserializeElement(reader, serializeCollectionKey);
          }
        }
      
        public class One : Parent
        {
          [ConfigurationProperty("p1")]
          public string P1
          {
            get
            {
              return (string)this["p1"];
            }
      
            set
            {
              this["p1"] = value;
            }
          }
        }
      
        public class Two : Parent
        {
          [ConfigurationProperty("p2")]
          public string P2
          {
            get
            {
              return (string)this["p2"];
            }
      
            set
            {
              this["p2"] = value;
            }
          }
        }
      
        public class Proxy : ConfigurationElement
        {
          private Parent _Parent = null;
      
          public Parent Parent
          {
            get
            {
              return _Parent;
            }
          }
      
          public Proxy()
          {
          }
      
          public Parent Instance
          {
            get
            {
              return _Parent;
            }
          }
      
          protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
          {
            string type = reader.GetAttribute("type");
            switch (type)
            {
              case "one":
                _Parent = new One();
                break;
              case "two":
                _Parent = new Two();
                break;
              default:
                throw new ArgumentException(string.Format("Invalid type: {0}", type));
            }
      
            _Parent.ProxyDeserializeElement(reader, serializeCollectionKey);
          }
        }
      
        public class CollectionConfig : ConfigurationElementCollection
        {
          public CollectionConfig()
          {
      
          }
      
          protected override ConfigurationElement CreateNewElement()
          {
            return new Proxy();
          }
      
          protected override Object GetElementKey(ConfigurationElement element)
          {
            return ((Proxy)element).Parent.Name;
          }
      
          public Parent this[int index]
          {
            get
            {
              return ((Proxy)BaseGet(index)).Parent;
            }
      
            set
            {
              if (BaseGet(index) != null)
              {
                BaseRemoveAt(index);
              }
      
              BaseAdd(index, value);
            }
          }
        }
      }
      

      App.config

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
       <configSections>
        <section name="CollectionSection" type="NestedConfiguration.CollectionSection, NestedConfiguration" />
       </configSections>
       <CollectionSection>
        <collection>
         <add type="one" name="one-1" p1="one-1 p1" />
         <add type="one" name="one-2" p1="one-2 p1" />
         <add type="two" name="two-1" p2="two-1 p2" />
        </collection>
       </CollectionSection>
      </configuration>
      

      Program.cs

      using System;
      using System.Collections.Generic;
      using System.Configuration;
      using System.Text;
      
      namespace NestedConfiguration
      {
        class Program
        {
          static void Main(string[] args)
          {
            try
            {
              ExeConfigurationFileMap map = new ExeConfigurationFileMap();
              map.ExeConfigFilename = "NestedConfiguration.exe.config";
              Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
              CollectionSection config = (CollectionSection)configuration.Sections[typeof(CollectionSection).Name];
              Console.WriteLine("Nested configurations: {0}", config.Collection.Count);
              foreach (Proxy proxy in config.Collection)
              {
                Console.WriteLine("Type: {0}", proxy.Parent.GetType());
              }
            }
            catch(Exception ex)
            {
              Console.WriteLine(ex.Message);
            }
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2010-10-25
        • 2010-11-12
        • 2013-09-17
        • 2011-07-04
        • 2012-12-12
        • 2013-09-21
        • 2011-10-02
        • 1970-01-01
        相关资源
        最近更新 更多