我有一个字符串字典,我希望用户能够添加/删除信息然后存储它们,以便下次程序重新启动时可以访问它
我不知道如何将字典存储为设置。我看到在system.collections.special下有一个叫做stringdictionary的东西,但我读过SD已经过时了,不应该使用。
将来我可能还需要存储一个非字符串的字典(int string)
如何将字典存储在.net应用程序的设置文件中?
答案 0 :(得分:43)
您可以使用从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>
...
答案 1 :(得分:15)
最简单的答案是使用一行&amp;用于将字典转换为单个字符串的列分隔符。然后你只需要在设置文件中存储1个字符串。
答案 2 :(得分:4)
如果您不需要使用设置设计器或使用文本编辑器编辑设置,则可以创建一个源自 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");
}
如果您希望字典序列化为用户可编辑的内容,则必须从Dictionary派生并使用TypeConverter播放(请参阅Using Custom Classes with Application Settings)。
答案 3 :(得分:3)
除了做David's suggests这样的事情之外,我会研究字典的备用存储。最终,Settings对象序列化为磁盘。
答案 4 :(得分:3)
您是否考虑过使用XML来存储字典?如果将来您决定要存储其他类型的词典,那么这将提供一定程度的可扩展性。您可以执行以下操作:
<dictionary>
<entry key="myKey">
[whatever data you like]
</entry>
</dictionary>
可能有点矫枉过正,但您也准备好要存储更复杂的数据,例如自定义对象。
答案 5 :(得分:2)
您还可以使用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);
}
答案 6 :(得分:1)
您可以创建一个将Dictionary公开为公共属性的自定义类。然后,您可以将此自定义类型指定为您的设置类型。
编辑:
我刚刚读到,由于某种原因,通用字典不能被XML序列化,所以我的解决方案可能无法工作(我还没有测试过它......)。这很奇怪,因为通用列表可以顺序排列而没有任何问题。
您仍然可以创建一个可以设置为用户设置的自定义类,但是您需要将列表公开为属性而不是字典。
答案 7 :(得分:1)
编辑:这将返回一个Hashtable(无论出于何种原因,尽管是'DictionarySectionHandler')。然而,由于Hashtables和Dictionaries是如此相似,它应该不是一个大问题(虽然我意识到字典更新,参数化等;我本来更喜欢dicitonaries,但这是.NET给我们的。)
我刚才找到的最佳答案是here。它返回一个类型安全的集合,没有代码中的任何混乱来转换它,并在.config文件中创建一个明显(和简单)的集合。我正在使用它,对于任何未来的程序员(包括你自己)来说都很直接。它允许更强的键入和更大的灵活性,而不需要任何过于复杂和不必要的解析。
答案 8 :(得分:1)
您可以存储StringCollection
。它类似于to this solution。
我制作了两种扩展方法,可以在StringCollection
和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();
}
}