Подтвердить что ты не робот

Сохранить словарь <строка, строкa> в настройках приложения

У меня есть словарь строк, который я хочу, чтобы пользователь мог добавлять/удалять информацию, а затем хранить его для них, чтобы они могли получить к нему доступ в следующий раз, когда программа перезагрузится

Непонятно, как я могу хранить словарь в качестве параметра. Я вижу, что в system.collections.special есть вещь, называемая stringdictionary, но ive читает, что SD устарели и не должны использоваться.

Также в будущем мне может понадобиться хранить словарь, который не является только строками (int string)

как вы будете хранить словарь в файле настроек для приложения .net?

4b9b3361

Ответ 1

Самый простой ответ - использовать разделитель строк и столбцов для преобразования словаря в одну строку. Тогда вам просто нужно сохранить 1 строку в файле настроек.

Ответ 2

Вы можете использовать этот класс, полученный из StringDictionary. Чтобы быть полезным для настроек приложения, он реализует IXmlSerializable. Или вы можете использовать аналогичный подход для реализации собственного класса XmlSerializable.

public class SerializableStringDictionary : StringDictionary, IXmlSerializable
{
    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        while (reader.Read() &&
            !(reader.NodeType == XmlNodeType.EndElement && reader.LocalName == this.GetType().Name))
        {
            var name = reader["Name"];
            if (name == null)
                throw new FormatException();

            var value = reader["Value"];
            this[name] = value;
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        foreach (DictionaryEntry entry in this)
        {
            writer.WriteStartElement("Pair");
            writer.WriteAttributeString("Name", (string)entry.Key);
            writer.WriteAttributeString("Value", (string)entry.Value);
            writer.WriteEndElement();
        }
    }
}

Результат XML-фрагмента будет выглядеть так:

...
<setting name="PluginSettings" serializeAs="Xml">
    <value>
        <SerializableStringDictionary>
            <Pair Name="property1" Value="True" />
            <Pair Name="property2" Value="05/01/2011 0:00:00" />
        </SerializableStringDictionary>
    </value>
</setting>
...

Ответ 3

Вместо того, чтобы делать что-то вроде Дэвид предлагает, я бы посмотрел на альтернативное хранилище для словаря. В конечном итоге объект "Настройки" сериализуется на диск.

Ответ 4

Рассматривали ли вы использование XML для хранения своего словаря? Это обеспечит определенную степень расширяемости, если в будущем вы решите, что хотите иметь возможность хранить другие типы словарей. Вы можете сделать что-то вроде:

<dictionary>
   <entry key="myKey">
      [whatever data you like]
   </entry>
</dictionary>

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

Ответ 5

Если вам не нужно использовать конструктор настроек или редактировать свои настройки с помощью текстового редактора, вы можете создать простой класс, который происходит из ApplicationSettingsBase:

namespace MyNamespace
{
    using System.Collections.Generic;
    using System.Configuration;

    /// <summary>
    /// Persistent store for my parameters.
    /// </summary>
    public class MySettings : ApplicationSettingsBase
    {
        /// <summary>
        /// The instance lock.
        /// </summary>
        private static readonly object InstanceLock = new object();

        /// <summary>
        /// The instance.
        /// </summary>
        private static MySettings instance;

        /// <summary>
        /// Prevents a default instance of the <see cref="MySettings"/> class 
        /// from being created.
        /// </summary>
        private MySettings()
        {
            // don't need to do anything
        }

        /// <summary>
        /// Gets the singleton.
        /// </summary>
        public static MySettings Instance
        {
            get
            {
                lock (InstanceLock)
                {
                    if (instance == null)
                    {
                        instance = new MySettings();
                    }
                }

                return instance;
            }
        }

        /// <summary>
        /// Gets or sets the parameters.
        /// </summary>
        [UserScopedSetting]
        [SettingsSerializeAs(SettingsSerializeAs.Binary)]
        public Dictionary<string, string> Parameters
        {
            get
            {
                return (Dictionary<string, string>)this["Parameters"];
            }

            set
            {
                this["Parameters"] = value;
            }
        }
    }
}

Реальный трюк - это атрибут [SettingsSerializeAs (SettingsSerializeAs.Binary)]. Большинство (все?) Классов могут быть сериализованы таким образом, где SettingsSerializeAs.String или SettingsSerializeAs.Xml не будут работать для Словаря.

Используйте это в своем коде, как и обычные настройки:

// this code untested...
MySettings.Instance.Parameters["foo"] = "bar";
MySettings.Instance.Parameters.Save();
MySettings.Instance.Parameters.Reload();
string bar;
if (!MySettings.Instance.Parameters.TryGetValue("foo", out bar))
{
    throw new Exception("Foobar");
}

Если вы хотите, чтобы Словарь сериализовался во что-то редактируемое пользователем, вы должны получить словарь и играть с TypeConverter (см. Использование пользовательских классов с настройками приложения).

Ответ 6

Вы можете создать пользовательский класс, который предоставляет словарь как общедоступное свойство. Затем вы можете указать этот настраиваемый тип как тип для своих настроек.

Изменить:

Я только что прочитал, что по какой-то причине общий словарь не может быть сериализован XML, поэтому мое решение, вероятно, не сработает (я его еще не протестировал, хотя...). Это странно, потому что общий список можно сериализовать без каких-либо проблем.

Вы все равно можете создать пользовательский класс, который можно установить как пользовательский параметр, но вам нужно будет иметь список, открытый как свойство, а не словарь.

Ответ 7

Вы также можете использовать System.Collections.Specialized.StringCollection, поместив ключ на четный индекс и значения на нечетный индекс.

/// <summary>
/// Emulate a Dictionary (Serialization pb)
/// </summary>
private static string getValue(System.Collections.Specialized.StringCollection list, string key)
{
    for (int i = 0; i * 2 < list.Count; i++)
    {
        if (list[i] == key)
        {
            return list[i + 1];
        }
    }
    return null;
}

/// <summary>
/// Emulate a Dictionary (Serialization pb)
/// </summary>      
private static void setValue(System.Collections.Specialized.StringCollection list, string key, string value)
{
    for (int i = 0; i * 2 < list.Count; i++)
    {
        if (list[i] == key)
        {
            list[i + 1] = value;
            return;
        }
    }
    list.Add(key);
    list.Add(value);
}

Ответ 8

Изменить: это вернет Hashtable (по какой-либо причине, несмотря на то, что это "DictionarySectionHandler" ). Однако, поскольку Hashtables и Dictionaries настолько схожи, это не должно быть большой проблемой (хотя я понимаю, что словари новее, параметризированы и т.д., Я бы предпочел сам диктонарий, но это то, что дает нам .NET).


Лучший ответ, который я только что нашел для этого, здесь. Он возвращает коллекцию типов с любым путаницей в коде, чтобы преобразовать ее, и вы создаете очевидную (и простую) коллекцию в вашем файле .config. Я использую это, и это довольно прямо для любого будущего программиста (включая самого себя). Это позволяет более набирать текст и больше гибкости, без чрезмерно сложного и ненужного разбора.

Ответ 9

Вы можете сохранить StringCollection. Это похоже на это решение.

Я сделал 2 метода расширения для преобразования между StringCollection и a Dictionary. Это самый простой способ, о котором я мог думать.

public static class Extender
{
    public static Dictionary<string, string> ToDictionary(this StringCollection sc)
    {
        if (sc.Count % 2 != 0) throw new InvalidDataException("Broken dictionary");

        var dic = new Dictionary<string, string>();
        for (var i = 0; i < sc.Count; i += 2)
        {
            dic.Add(sc[i], sc[i + 1]);
        }
        return dic;
    }

    public static StringCollection ToStringCollection(this Dictionary<string, string> dic)
    {
        var sc = new StringCollection();
        foreach (var d in dic)
        {
            sc.Add(d.Key);
            sc.Add(d.Value);
        }
        return sc;
    }
}

class Program
{
    static void Main(string[] args)
    {
        //var sc = new StringCollection();
        //sc.Add("Key01");
        //sc.Add("Val01");
        //sc.Add("Key02");
        //sc.Add("Val02");

        var sc = Settings.Default.SC;

        var dic = sc.ToDictionary();
        var sc2 = dic.ToStringCollection();

        Settings.Default.SC = sc2;
        Settings.Default.Save();
    }
}