【问题标题】:Is there a way to use a dictionary or xml in the Application Settings?有没有办法在应用程序设置中使用字典或 xml?
【发布时间】:2011-02-09 11:12:51
【问题描述】:

我必须在应用程序设置中存储一个复杂类型。我认为将其存储为 XML 效果最好。

问题是我不知道如何存储 XML。我更喜欢将其存储为托管 XML,而不是仅使用必须在每次访问时解析它的原始 XML 字符串。我设法将设置的Type 列设置为 XDocument,但我无法设置它的值。

有没有办法在应用程序设置中使用 XDocument 或 XML?

更新

我找到了一种方法,只需使用 xml 编辑器编辑 .settings 文件即可。

我将其更改为custom serializable dictionary,但当我尝试访问设置属性时出现以下错误(我将其设置为默认值的序列化表示形式)。

The property 'Setting' could not be created from it's default value.
Error message: There is an error in XML document (1, 41).

任何想法都会受到赞赏。

【问题讨论】:

    标签: xml vb.net dictionary linq-to-xml application-settings


    【解决方案1】:

    我所做的(即使我不太喜欢 - 但有效)是:

    我为我的值创建了简单的可序列化类:

    <Xml.Serialization.XmlRoot("Rooms")> _
    Public Class Rooms : Inherits List(Of Room)
    End Class
    
    <Serializable()> _
    Public Class Room
        Private m_Room As String
        Public Property Room() As String
            Get
                Return m_Room
            End Get
            Set(ByVal value As String)
                m_Room = value
            End Set
        End Property
    
        Private m_Sections As New List(Of Section)
        Public ReadOnly Property Sections() As List(Of Section)
            Get
                Return m_Sections
            End Get
        End Property
    End Class
    
    <Serializable()> _
    Public Class Section
        Private m_Section As String
        Public Property Section() As String
            Get
                Return m_Section
            End Get
            Set(ByVal value As String)
                m_Section = value
            End Set
        End Property
    End Class
    

    然后在 .settings 文件中,我将设置的类型(使用 xml 编辑器打开的 .setting 文件)编辑为 Rooms 的全名(即 MyProject.Rooms)。 然后我为自己制作了一个反序列化示例并将其复制到 .settings 编辑器中的 value 字段以获得默认值。效果很好。 它确实不是字典,但我仍然可以在 Rooms 类和内部字典中实现(按 Room.Room 返回 Sections。

    仍然欢迎任何好的想法,我仍在寻找能够在 .settings 文件中使用 IDictinoarys 的方法。

    另外,我为它开了一个connection,请善待并投票!

    【讨论】:

      【解决方案2】:

      我最终做了什么,因为这是阻力最小的路径,即使用 .NET Fx 中的内置配置类。即使下面的代码是用 C# 编写的,您也应该能够轻松地将其转换为 VB.NET(或将其编辑并编译成您可以从项目中引用的程序集)。

      您会注意到,ConfigurationElementCollection 类可以轻松转换为键/值对字典(您可能必须对值对使用反射,或者要存储为值对的类可以采用设置类从 ConfigurationElement 作为构造函数参数继承)。

      // ConfigurationElement.cs
      public class ConfigurationElement : System.Configuration.ConfigurationElement
      {
          protected T GetValue<T>(string key, T defaultValue)
          {
              var value = default(T);
              if (base[key] != null)
              {
                  var str = base[key].ToString();
                  try
                  {
                      if (!String.IsNullOrEmpty(str))
                          value = (T)Convert.ChangeType(str, typeof(T));
                  }
                  catch // use the default
                  {
                  }
              }
      
              return value;
          }
      }
      
      // ConfigurationElementCollection.cs
      public abstract class ConfigurationElementCollection<TElement,TKey> : 
          ConfigurationElementCollection, 
          IEnumerable<TElement> where TElement : System.Configuration.ConfigurationElement, new()
      {
          public TElement this[int index]
          {
              get { return (TElement)BaseGet(index); }
          }
      
          public TElement this[TKey key]
          {
              get { return (TElement)BaseGet(key); }
          }
      
          protected override System.Configuration.ConfigurationElement CreateNewElement()
          {
              return new TElement();
          }
      
          protected override object GetElementKey(System.Configuration.ConfigurationElement element)
          {
              return GetElementKey((TElement)element);
          }
          protected abstract TKey GetElementKey(TElement element);
      
          public TKey[] GetAllKeys()
          {
              var keys = BaseGetAllKeys();
              var ret = new TKey[keys.Length];
              for (var i = 0; i < keys.Length; i++)
                  ret[i] = (TKey)keys[i];
      
              // done
              return ret; 
          }
          public void Add(TElement element)
          {
              BaseAdd(element);
          }
          public void Remove(TElement element)
          {
              BaseRemove(element);
          }
          public void Clear()
          {
              BaseClear();
          }
      
          IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
          {
              foreach (TElement element in this)
              {
                  yield return element;
              }
          }
      
          System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
          {
              throw new System.NotImplementedException();
          }
      }
      

      这是一个示例,我在系统中将上述基类代码用于我们的分片策略(更改名称以保护无辜者):

      <!-- web.config -->
      <!-- ... -->
      <configuration>
          <configSections>
              <section name="sharding" type="Domain.ShardingSection, Domain.Configuration" />
          </configSections>
      </configuration>
      <!-- ... -->
      <sharding>
          <configurationMappings>
              <add lastDigit="0" sqlMapFileName="Shard-0.SqlMap.config" />
              <add lastDigit="1" sqlMapFileName="Shard-1.SqlMap.config" />
              <add lastDigit="2" sqlMapFileName="Shard-2.SqlMap.config" />
              <add lastDigit="3" sqlMapFileName="Shard-3.SqlMap.config" />
              <add lastDigit="4" sqlMapFileName="Shard-4.SqlMap.config" />
              <add lastDigit="5" sqlMapFileName="Shard-5.SqlMap.config" />
              <add lastDigit="6" sqlMapFileName="Shard-6.SqlMap.config" />
              <add lastDigit="7" sqlMapFileName="Shard-7.SqlMap.config" />
              <add lastDigit="8" sqlMapFileName="Shard-8.SqlMap.config" />
              <add lastDigit="9" sqlMapFileName="Shard-9.SqlMap.config" />
          </configurationMappings>
      </sharding>
      

      然后是上面XML实例所代表的配置类:

      // ShardElement.cs
      public class ShardElement : ConfigurationElement
      {
          [ConfigurationProperty("lastDigit", IsKey=true, IsRequired=true)]
          public int LastDigit
          {
              get { return (int)this["lastDigit"]; }
          }
      
          [ConfigurationProperty("sqlMapFileName", IsRequired=true)]
          public string SqlMapFileName
          {
              get { return (string)this["sqlMapFileName"]; }
          }
      }
      
      // ShardElementCollection.cs
      public class ShardElementCollection : ConfigurationElementCollection<ShardElement, int>
      {
          protected override int GetElementKey(ShardElement element)
          {
              return element.LastDigit;
          }
      }
      
       // ShardingSection.cs
       public class ShardingSection : ConfigurationSection
      {
          public const string Name = "sharding";
      
          [ConfigurationProperty("configurationMappings")]
          public ShardingElementCollection ConfigurationMappings
          {
              get { return (ShardingElementCollection)base["configurationMappings"]; }
          }
      }
      

      虽然它在 *.config 文件中不是真正的 IDictionary,但它可以处理该作业,并且如果您的配置文件在运行时更新,您无需重新启动应用程序或回收 AppPool 即可获取新值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-04
        • 1970-01-01
        • 2015-07-16
        • 2010-09-14
        相关资源
        最近更新 更多