如何在用户设置中存储哈希表? [英] How to store a HashTable in the usersettings?
问题描述
在.NET中,您可以选择一个哈希表作为用户设置的类型.但是,当我保存并以这种方式检索它时,它似乎根本没有保存.
In .NET you can select a hashtable as type for a usersetting. However when I save it and retrieve it in this way, it doesnt seem to have saved it at all.
Hashtable t = new Hashtable();
t.Add(1,"Foo");
t.Add(2,"Bar");
Properties.Settings.Default.Setting = t;
Properties.Settings.Default.Save();
if(Properties.Settings.Default.Setting != null)
foreach (DictionaryEntry entry in Properties.Settings.Default.Setting)
{
MessageBox.Show(entry.Key + " " + entry.Value);
}
当我可以在Visual Studio中清楚地选择该类型时,为什么不在用户设置中对其进行序列化?我会理解未列出类型(例如字典)是否属于这种情况,但是列出了Hashtable.我该如何解决这个问题?
对于我而言,按此顺序排列的简单性和效率是最重要的.
Why doesnt it serialize it in the usersettings, when I can clearly select that type in Visual studio? I would understand if this was the case with an unlisted type such as dictionary, but Hashtable is listed. How do I solve this problem?
Simplicity and efficiency in this order have the highest priority for me.
非常感谢, 冒犯
更新:
@Joao,非常感谢Binary解决方案.我觉得它很有趣,很干净.将其序列化为二进制的一个缺点可能是您无法再手动更改用户设置文件中的任何内容.但是我认为无论如何很少会这样做,所以这是一个很好的解决方案.
@Joao , Many Thanks the Binary solution. I find it quite interesting, its clean. One disadvavtage with serializing it as binary might be the fact that you cant change anything in the usersetting file manually anymore. but I think that will be done very rarely anyway, so its a good solution.
我在想一种不同的方法来在用户范围内创建字符串类型的"XMLSetting"字段,并使用此代码存储和检索作为序列化为哈希表的XM1文件的值.但是我确信这不是最好的方法,除了我在下面做的事情之外,没有人知道在用户设置中将哈希表/字典序列化为xml的更好的方法吗?
I was thinking of a different approach to create an "XMLSetting" field of type string in the user scope and use this code to store and retrieve the values as an XMl file serialized into a hashtable. But I am sure this is not the best way, does anyone know a better way to serialize a hashtable/dictionary as xml in the usersettings, other than what i am doing below?
if(string.IsNullOrEmpty(Properties.Settings.Default.XMLSetting))
{
Console.WriteLine("Usersettings is empty. Initializing XML file...");
XmlDocument doc = new XmlDocument();
XmlElement hashtable = doc.CreateElement("HashTable");
doc.AppendChild(hashtable);
GenerateValues(doc, hashtable, "1", "Foo");
GenerateValues(doc, hashtable, "2", "Bar");
Properties.Settings.Default.XMLSetting = doc.OuterXml;
Properties.Settings.Default.Save();
}
else
{
Console.WriteLine("Retrieving existing user settings...");
XmlDocument doc = new XmlDocument();
doc.LoadXml(Properties.Settings.Default.XMLSetting);
Hashtable hashtable = new Hashtable();
foreach (XmlNode entry in doc.DocumentElement.ChildNodes)
{
hashtable.Add(int.Parse(entry.FirstChild.InnerText), entry.FirstChild.NextSibling.InnerText);
}
foreach (DictionaryEntry entry in hashtable)
{
Console.WriteLine(entry.Key + " " + entry.Value);
}
}
private static void GenerateValues(XmlDocument doc, XmlElement hashtable, string skey, string svalue)
{
XmlElement entry = doc.CreateElement("entry");
XmlElement key = doc.CreateElement("Key");
XmlElement value = doc.CreateElement("Value");
entry.AppendChild(key);
entry.AppendChild(value);
key.AppendChild(doc.CreateTextNode(skey));
value.AppendChild(doc.CreateTextNode(svalue));
hashtable.AppendChild(entry);
}
推荐答案
哈希表不支持序列化为XML,也不支持简单字符串.当您使用Settings.settings文件和关联的自动生成的类时,这是两个可用的序列化选项.
The Hashtable does not support serialization to XML nor I believe to a simple string. These are the two serialization options available when you use a Settings.settings file and the associated auto-generated class.
但是,如果您自己创建设置类并管理App.Config部分,则可以使用二进制序列化来持久化Hastable.
However if you create your settings class by yourself and also manage the App.Config section you can persist an Hastable by using Binary serialization.
请参见以下示例.这是一个具有以下文件的控制台应用程序:
See the following example. It's a console application with following files:
App.config
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup
name="userSettings"
type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section
name="ConsoleApplication1.MyCustomSettings"
type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<ConsoleApplication1.MyCustomSettings>
<setting name="MyHashtable" serializeAs="Binary">
<value></value>
</setting>
<setting name="MyBackColor" serializeAs="String">
<value>Silver</value>
</setting>
</ConsoleApplication1.MyCustomSettings>
</userSettings>
</configuration>
手动创建的自定义设置类别:
Custom Settings Class created manually:
public class MyCustomSettings : ApplicationSettingsBase
{
private static MyCustomSettings defaultInstance = (
(MyCustomSettings)
(ApplicationSettingsBase.Synchronized(new MyCustomSettings())));
public static MyCustomSettings Default
{
get { return defaultInstance; }
}
[UserScopedSettingAttribute()]
[DebuggerNonUserCodeAttribute()]
[DefaultSettingValueAttribute("Silver")]
public Color MyBackColor
{
get { return ((Color)(this["MyBackColor"])); }
set { this["MyBackColor"] = value; }
}
[UserScopedSettingAttribute()]
[DebuggerNonUserCodeAttribute()]
[SettingsSerializeAs(SettingsSerializeAs.Binary)]
public Hashtable MyHashtable
{
get { return ((Hashtable)(this["MyHashtable"])); }
set { this["MyHashtable"] = value; }
}
}
Program.cs
Program.cs
class Program
{
static void Main(string[] args)
{
// For the first time no Hastable will exist.
// Create one with the default values
if (MyCustomSettings.Default.MyHashtable == null)
{
Console.WriteLine("Initializing Hashtable...");
MyCustomSettings.Default.MyHashtable = new Hashtable();
MyCustomSettings.Default.MyHashtable.Add(1, "foo");
MyCustomSettings.Default.MyHashtable.Add(2, "bar");
MyCustomSettings.Default.Save();
}
foreach (DictionaryEntry entry in MyCustomSettings.Default.MyHashtable)
{
Console.WriteLine(entry.Key + ": " + entry.Value);
}
Console.ReadKey();
}
}
更新: 如果您想用一种人类可读的数据表示形式,那么您所使用的方法似乎是合理的.尽管如此,您还可以尝试另一种方法,该方法更好地封装了转换为字符串(XML)和从字符串(XML)转换的逻辑.
Update: If you want a human readable representation of the data, the approach you're using seems reasonable. Nonetheless you can also try a different approach that better encapsulates the logic of converting to string (XML) and from string (XML).
这种方法允许您使用IDE对Settings.settings文件的支持,而无需生成自定义设置类或与App.config混淆.
This approach allows you to use the IDE support for Settings.settings file removing the need to generate a custom setting class or messing with App.config.
您只需要实现一个自定义类即可保存您的数据,在我的示例中,我将从StringDictionary继承该类,还实现一个
You just need to implement a custom class that will hold your data, in my example I will inherit this class from a StringDictionary and also implement a TypeConverter that the settings system will use to persist the data in string format.
[TypeConverter(typeof(StringDictionaryTypeConverter))]
public class MyStringDictionary : StringDictionary
{
}
public class StringDictionaryTypeConverter : TypeConverter
{
public override bool CanConvertFrom(
ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType.Equals(typeof(string)))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(
ITypeDescriptorContext context,
Type destinationType)
{
if (destinationType.Equals(typeof(string)))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(
ITypeDescriptorContext context,
CultureInfo culture,
object value)
{
if (value is string)
{
MyStringDictionary sd = new MyStringDictionary();
XDocument xs = XDocument.Load(new StringReader(value as string));
foreach (var item in xs.Descendants("entry"))
{
sd.Add(item.Element("key").Value, item.Element("value").Value);
}
return sd;
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(
ITypeDescriptorContext context,
CultureInfo culture,
object value,
Type destinationType)
{
if (destinationType.Equals(typeof(string)))
{
MyStringDictionary sd = value as MyStringDictionary;
StringBuilder sb = new StringBuilder();
sb.Append("<entries>");
foreach (DictionaryEntry item in sd)
{
sb.AppendFormat(
"<entry><key>{0}</key><value>{1}</value></entry>",
item.Key,
item.Value);
}
sb.Append("</entries>");
return sb.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
现在,您只需要使用MyStringDictionary类作为设置的数据类型.由于Visual Studio不在用户设置的可用数据类型中显示用户类别,因此您需要采取一种一次性解决方法,其中包括使用XML编辑器(右键单击和打开宽度)打开Settings.settings文件,然后手动指定用户设置的类型,作为MyStringDictionary的全名.
Now you just need to use the MyStringDictionary class as the data type of your settings. Due to Visual Studio not displaying user classes in the available data types for a user setting you need to do a one time workaround that consists of opening the Settings.settings file with the XML editor (Right-click and Open Width) and manually specify the type of the user setting as the full name of MyStringDictionary.
希望这会有所帮助.
这篇关于如何在用户设置中存储哈希表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!