C# 在应用程序设置中存储 Dictionary<string,string>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/922047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:15:49  来源:igfitidea点击:

Store Dictionary<string,string> in application settings

c#.net-3.5dictionarysettings

提问by Crash893

I have a dictionary of strings that i want the user to be able to add/remove info from then store it for them so it they can access it the next time the program restarts

我有一个字符串字典,我希望用户能够添加/删除信息,然后为他们存储它,以便他们可以在下次程序重新启动时访问它

I am unclear on how i can store a dictionary as a setting. I see that under system.collections.special there is a thing called a stringdictionary but ive read that SD are outdated and shouldn't be used.

我不清楚如何将字典存储为设置。我看到在 system.collections.special 下有一个叫做 stringdictionary 的东西,但我读到 SD 已经过时,不应该使用。

also in the future i may have need to store a dictionary that is not strings only (int string)

同样在将来,我可能需要存储一个不仅仅是字符串的字典(int string)

how would you store a dictionary in the settings file for a .net application?

您将如何在 .net 应用程序的设置文件中存储字典?

采纳答案by David

The simplest answer would be to use a row & column delimiter to convert your dictionary to a single string. Then you just need to store 1 string in the settings file.

最简单的答案是使用行和列分隔符将字典转换为单个字符串。然后你只需要在设置文件中存储 1 个字符串。

回答by Erik Forbes

Other than doing something like David's suggests, I would look into alternate storage for the Dictionary. Ultimately the Settings object serializes to disk.

除了像大卫的建议那样做一些事情之外,我会研究字典的替代存储。最终设置对象序列化到磁盘。

回答by Meta-Knight

You could create a custom class that exposes a Dictionary as a public property. Then you can specify this custom type as the type for your setting.

您可以创建一个将 Dictionary 公开为公共属性的自定义类。然后您可以将此自定义类型指定为您的设置的类型。

Edit:

编辑:

I have just read that, for some reason, a generic dictionary cannot be XML-serialized, so my solution will probably not work (I haven't tested it though...). That's strange, because a generic list can be serialized without any problem.

我刚刚读到,出于某种原因,通用字典不能进行 XML 序列化,所以我的解决方案可能不起作用(不过我还没有测试过......)。这很奇怪,因为泛型列表可以毫无问题地序列化。

You could still create a custom class that can be set as a user setting, but you will need to have a list exposed as a property instead of a dictionary.

您仍然可以创建一个可以设置为用户设置的自定义类,但您需要将列表公开为属性而不是字典。

回答by Ender

Have you considered using XML to store your dictionary? That would provide a certain amount of extensibility if in the future you decide you want to be able to store other types of dictionaries. You might do something like:

您是否考虑过使用 XML 来存储您的字典?如果将来您决定希望能够存储其他类型的词典,这将提供一定程度的可扩展性。您可能会执行以下操作:

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

Might be overkill, but you'd also be prepared in the case that you wanted to store more complex data, like custom objects.

可能有点矫枉过正,但您也应该准备好存储更复杂的数据,例如自定义对象。

回答by Olivier de Rivoyre

You can also use a System.Collections.Specialized.StringCollection by putting key on even index and values on odd index.

您还可以通过将键放在偶数索引上并将值放在奇数索引上来使用 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);
}

回答by James

Edit: This will return a Hashtable (for whatever reason, despite being a 'DictionarySectionHandler'). However, being that Hashtables and Dictionaries are so similar, it shouldn't be a large issue (though I realize Dictionaries are newer, parameterized, etc; I would have preferred dicitonaries myself, but this is what .NET gives us).

编辑:这将返回一个哈希表(无论出于何种原因,尽管是“DictionarySectionHandler”)。然而,由于 Hashtables 和 Dictionaries 如此相似,这应该不是一个大问题(尽管我意识到 Dictionaries 更新、参数化等;我自己更喜欢字典,但这就是 .NET 给我们的)。



The best answer I just found for this is here. It returns a typesafe collection witout any muddling in code to transform it, and you create an obvious (and simple) collection in your .config file. I'm using this and it's quite straight forward for any future programmer (including yourself). It allows for stronger typing and more flexibility, without any overly-complicated and unnecessary parsing.

我刚刚为此找到的最佳答案是here。它返回一个类型安全的集合,在转换它的代码中没有任何混乱,并且您在 .config 文件中创建了一个明显(且简单)的集合。我正在使用它,这对任何未来的程序员(包括你自己)来说都是非常直接的。它允许更强大的类型和更大的灵活性,没有任何过于复杂和不必要的解析。

回答by BrunoLM

You can store a StringCollection. It is similar to this solution.

您可以存储一个StringCollection. 它类似于此解决方案

I made 2 extension methods to convert between StringCollectionand a Dictionary. This is the easiest way I could think of.

我做了2种扩展方法之间进行转换StringCollectionDictionary。这是我能想到的最简单的方法。

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();
    }
}

回答by Seva Parfenov

You can use this class derived from StringDictionary. To be useful for application settings it implements IXmlSerializable. Or you can use similar approach to implement your own XmlSerializable class.

您可以使用从 StringDictionary 派生的此类。为了对应用程序设置有用,它实现了 IXmlSerializable。或者您可以使用类似的方法来实现您自己的 XmlSerializable 类。

public class SerializableStringDictionary : System.Collections.Specialized.StringDictionary, System.Xml.Serialization.IXmlSerializable
{
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        while (reader.Read() &&
            !(reader.NodeType == System.Xml.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(System.Xml.XmlWriter writer)
    {
        foreach (System.Collections.DictionaryEntry entry in this)
        {
            writer.WriteStartElement("Pair");
            writer.WriteAttributeString("Name", (string)entry.Key);
            writer.WriteAttributeString("Value", (string)entry.Value);
            writer.WriteEndElement();
        }
    }
}

Resulting XML fragment will look similar to:

生成的 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>
...

回答by mheyman

If you don't need to use the settings designer or edit your settings with a text editor, you can create a simple class that derives from ApplicationSettingsBase:

如果您不需要使用设置设计器或使用文本编辑器编辑您的设置,您可以创建一个派生自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;
            }
        }
    }
}

The real trick is the [SettingsSerializeAs(SettingsSerializeAs.Binary)]attribute. Most (all?) classes can get serialized this way where SettingsSerializeAs.Stringor SettingsSerializeAs.Xmlwont work for a Dictionary.

真正的技巧是[SettingsSerializeAs(SettingsSerializeAs.Binary)]属性。大多数(所有?)类都可以通过这种方式序列化,其中SettingsSerializeAs.StringSettingsSerializeAs.Xml不适用于字典。

Use this in your code as you would normal settings:

在您的代码中像正常设置一样使用它:

// 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");
}

If you want the Dictionary to serialize into something user editable, you must derive from Dictionary and play with TypeConverter (see Using Custom Classes with Application Settings).

如果您希望 Dictionary 序列化为用户可编辑的内容,则必须从 Dictionary 派生并使用 TypeConverter(请参阅在应用程序设置中使用自定义类)。