2010-04-18 4 views
4

Мне нужно сохранить сложный тип в настройках приложения. Я думал, что хранение его как XML будет работать лучше всего.Есть ли способ использовать словарь или xml в настройках приложения?

Проблема в том, что я не знаю, как хранить XML. Я предпочитаю хранить его как управляемый XML, а не использовать только строку необработанного XML, которая должна анализировать его при каждом доступе. Мне удалось установить столбец Type параметра XDocument, но я не смог установить его значение.

Есть ли способ использовать XDocument или XML в настройках приложения?

Update

Я нашел способ, просто отредактировав .settings файл с помощью редактора XML.

Я изменил его на 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). 

Любые идеи будут оценены.

ответ

2

То, что я сделал (даже я не люблю так много - но работает) является:

Я создал простые сериализуемые классы моих значений:

<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 я отредактировал тип настройки (файл .setting, открытый с помощью редактора xml), до полного имени комнат (например, MyProject.Rooms). Затем я сделал себе образец десериализованного образца и скопировал его в поле значения в редакторе .settings, чтобы иметь значение по умолчанию. он отлично работает. Это действительно не словарь, но я все еще мог реализовать в классе и внутреннем словаре Rooms (который возвращает разделы по номеру.

Любые хорошие идеи по-прежнему приветствуются, я все еще ищу способ быть способным использовать IDictinoary с в файле .settings.

Кроме того, я открыл 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"]; } 
    } 
} 

Хотя его не так IDictionary в * .config файл, он может справиться с этой задачей, и если ваш конфигурационный файл обновляется во время выполнения вы не должны перезапустите приложение или перезапустите AppPool, чтобы получить новые значения.

Смежные вопросы