2009-11-21 2 views
5

.NETでは、ユーザー設定のタイプとしてハッシュテーブルを選択できます。しかし、私はそれを保存し、このように取得すると、それはまったくそれを保存していないようです。HashTableをusersettingsに保存するには?

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がリストされています。この問題をどうやって解決するのですか?
この順番で単純さと効率が私にとって最優先事項です。

多くのおかげで、 KAVE


更新:

@Joao、多くのおかげでバイナリソリューション。私はそれが非常に面白い、清潔であることがわかります。バイナリとしてそれをシリアル化することの1つの欠点は、ユーザー設定ファイル内の何も手動で変更することができないという事実かもしれません。しかし、私はそれがとにかくまれにしか行われないだろうと思うので、良い解決策です。

私は、ユーザースコープに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); 
     } 
+0

私はちょうどユーザ設定としてHashtableを持続させテストし、問題を検出しませんでした。まだ行っていない場合は、新しいテストプロジェクトでゼロから試してみてください。 –

+0

こんにちは、もう一度試しました。 Properties.Settings.Default.Settingは、アプリケーションを保存して再起動した後でも、nullのままとしています。それは他のタイプの文字列でも動作します。どうやってそれを稼働させましたか?何とかあなたのソリューションを投稿できますか? – Houman

+0

私はテストで急いでいました。ハッシュテーブルは、デフォルトの設定クラスでのアプリケーション実行の間に保持されません。しかし、あなたがHashtableを持っていて手作業を気にしなければ、私の答えをチェックすることができます。 –

答えて

12

HashtableはXMLへのシリアライズをサポートしていません。シンプルな文字列もありません。これらは、Settings.settingsファイルと関連する自動生成クラスを使用する場合に使用できる2つのシリアル化オプションです。

自分で設定クラスを作成し、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> 

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の

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も実装します。

[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エディタ(Right-click and Open Width)でSettings.settingsファイルを開き、 MyStringDictionaryのフルネームとしてユーザー設定の種類を指定します。

これが役に立ちます。

+0

これは今、多くのおかげで動作します。私はこの問題に新しい解決法を加えました。あれについてどう思う?最適化の提案はありますか? – Houman

+0

更新をチェック... –

+0

ありがとう。これも同様に機能しました。今私たちはこの問題に対する3つの解決策を持っています。 :o) – Houman

関連する問題