.net 如何在usersettings中存储哈希表?
在.NET中,您可以选择哈希表作为用户设置的类型。然而,当我以这种方式保存和检索它时,它似乎根本没有保存它.net 如何在usersettings中存储哈希表?,.net,hashtable,settings,.net,Hashtable,Settings,在.NET中,您可以选择哈希表作为用户设置的类型。然而,当我以这种方式保存和检索它时,它似乎根本没有保存它 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)
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);
}
当我可以在VisualStudio中清楚地选择该类型时,为什么不在usersettings中序列化它呢?我可以理解,如果未列出的类型(如dictionary)是这种情况,但Hashtable是列出的。如何解决这个问题?这一顺序中的简单性和效率对我来说是最重要的 非常感谢,, 卡夫
更新: @Joao,非常感谢二进制解决方案。我觉得很有趣,很干净。将其序列化为二进制的一个缺点可能是,您无法再手动更改usersetting文件中的任何内容。但我认为,无论如何,这将是非常罕见的,所以这是一个很好的解决方案 我正在考虑另一种方法,在用户范围内创建一个string类型的“XMLSetting”字段,并使用此代码将值存储和检索为序列化为哈希表的XMl文件。但我确信这不是最好的方法,除了我下面所做的工作之外,还有谁知道在usersettings中将哈希表/字典序列化为xml的更好方法吗
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文件和关联的自动生成类时可用的两个序列化选项 但是,如果您自己创建设置类并管理App.Config部分,则可以使用二进制序列化来持久化Hastable 请参见下面的示例。它是一个控制台应用程序,包含以下文件: 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>
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)的逻辑
这种方法允许您使用IDE对Settings.Settings文件的支持,从而无需生成自定义设置类,也无需修改App.config
您只需要实现一个保存数据的自定义类,在我的示例中,我将从StringDictionary继承这个类,并实现一个设置系统将用于以字符串格式保存数据的类
[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);
}
}
[TypeConverter(typeof(StringDictionaryTypeConverter))]
公共类MyStringDictionary:StringDictionary
{
}
公共类StringDictionaryTypeConverter:TypeConverter
{
公共覆盖布尔CanConvertFrom(
ITypeDescriptorContext上下文,
类型(源类型)
{
if(sourceType.Equals(typeof(string)))
{
返回true;
}
返回base.CanConvertFrom(上下文,sourceType);
}
公共覆盖布尔CanConvertTo(
ITypeDescriptorContext上下文,
类型destinationType)
{
if(destinationType.Equals(typeof(string)))
{
返回true;
}
返回base.CanConvertTo(上下文,destinationType);
}
公共重写对象转换自(
ITypeDescriptorContext上下文,
文化资讯文化,
对象值)
{
if(值为字符串)
{
MyStringDictionary sd=新MyStringDictionary();
XDocument xs=XDocument.Load(新的StringReader(值为字符串));
foreach(xs.subjects(“条目”)中的变量项)
{
添加(项目元素(“键”)值,项目元素(“值”)。值);
}
返回sd;
}
返回base.ConvertFrom(上下文、区域性、值);
}
公共覆盖对象转换为(
ITypeDescriptorContext上下文,
文化资讯文化,
对象值,
类型destinationType)
{
if(destinationType.Equals(typeof(string)))
{
MyStringDictionary sd=作为MyStringDictionary的值;
StringBuilder sb=新的StringBuilder();
某人加上(“”);
foreach(字典输入sd中的项目)
{
附文格式(
"{0}{1}",
项目.关键,
项目(价值);
}
某人加上(“”);
使某人返回字符串();
}
返回base.ConvertTo(上下文、区域性、值、destinationType);
}
}
现在您只需要使用MyStringDictionary类作为设置的数据类型。由于Visual Studio未在用户设置的可用数据类型中显示用户类,您需要执行一次性解决方案,包括使用XML编辑器打开Settings.Settings文件(右键单击并打开宽度),然后手动将用户设置的类型指定为MyStringDictionary的全名
希望这有帮助。我刚刚测试了将哈希表持久化为用户设置,没有发现任何问题。如果你还没有做过,试着在一个新的测试项目中从头开始做。嗨,我刚刚又做了一次。即使在我保存并重新启动应用程序后,它仍会将Properties.Settings.Default.Setting保持为null。但它也适用于其他类型,如字符串。你是怎么做到的?你能发布你的解决方案吗?我的测试太仓促了。哈希表不会在使用默认设置类的应用程序运行之间持久化。不过,如果有一个哈希表对您来说很重要,并且不介意一些手工工作,您可以检查我的答案。现在可以了,非常感谢。我还为这个问题添加了一个新的解决方案。你觉得怎么样?有什么优化建议吗?非常感谢。这也起了作用。现在我们有三种解决这个问题的方法o) 这是一个更好的实现,它使用“真实”XML,而不是手动输入etc内容:最后一点,要将新类型作为您设置的数据类型,首先构建应用程序,然后在
[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);
}
}