2009-11-21 8 views
5

.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) 
     foreach (DictionaryEntry entry in Properties.Settings.Default.Setting) 
     { 
      MessageBox.Show(entry.Key + " " + entry.Value); 
     } 

यह उपयोगकर्ताओं को सेटिंग्स में क्रमबद्ध क्यों नहीं करता है, जब मैं स्पष्ट रूप से उस दृश्य स्टूडियो में उस प्रकार का चयन कर सकता हूं? मैं समझूंगा कि यह एक असूचीबद्ध प्रकार के साथ शब्द था, जैसे कि शब्दकोश, लेकिन हैशटेबल सूचीबद्ध है। मैं इस समस्या का समाधान कैसे कर सकता हूं।
इस आदेश में सरलता और दक्षता मेरे लिए सर्वोच्च प्राथमिकता है।

कई धन्यवाद, Kave


अद्यतन:

@Joao, कई धन्यवाद बाइनरी समाधान। मुझे यह काफी रोचक लगता है, यह साफ है। द्विआधारी के रूप में इसे क्रमबद्ध करने के साथ एक अव्यवस्था यह तथ्य हो सकता है कि आप मैन्युअल रूप से उपयोगकर्तासेट फ़ाइल में कुछ भी नहीं बदल सकते हैं। लेकिन मुझे लगता है कि वैसे भी बहुत ही कम किया जाएगा, इसलिए यह एक अच्छा समाधान है।

मैं उपयोगकर्ता स्कोप में टाइप स्ट्रिंग के "एक्सएमएलसेटिंग" फ़ील्ड को बनाने के लिए एक अलग दृष्टिकोण के बारे में सोच रहा था और इस कोड का उपयोग एक एक्सएमएल फ़ाइल को एक हैशटेबल में क्रमबद्ध करने के लिए स्टोर और पुनर्प्राप्त करने के लिए करता हूं। लेकिन मुझे यकीन है कि यह सबसे अच्छा तरीका नहीं है, क्या किसी को हैशटेबल/डिक्शनरी को उपयोगकर्ताेटिंग में एक्सएमएल के रूप में क्रमबद्ध करने का बेहतर तरीका पता है, जो मैं नीचे कर रहा हूं उसके अलावा?

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

मैंने अभी एक हैशटेबल को उपयोगकर्ता सेटिंग के रूप में बनाए रखने का परीक्षण किया है और कोई समस्या नहीं मिली है। यदि आपने इसे पहले से नहीं किया है, तो इसे एक नई टेस्ट प्रोजेक्ट में स्क्रैच से करने का प्रयास करें। –

+0

हाय, मैंने अभी कोशिश की है। यह गुणों को एसएसएइंग रखता है। सेटिंग्स। डिफॉल्ट। स्टेटिंग को शून्य के रूप में रहता है, भले ही मैंने सहेजा और एप्लिकेशन को पुनरारंभ किया। हालांकि यह अन्य प्रकार के स्ट्रिंग के साथ काम करता है। आप इसे कैसे काम करते हैं? क्या आप अपना समाधान किसी भी तरह पोस्ट कर सकते हैं? – Houman

+0

मैं अपने परीक्षणों में जल्दबाजी करना चाहता था। डिफ़ॉल्ट सेटिंग्स वर्ग के साथ एप्लिकेशन रन के बीच हैशटेबल जारी नहीं है। हालांकि यदि आपके लिए हैशटेबल होना महत्वपूर्ण है और कुछ मैन्युअल कार्य नहीं करते हैं, तो आप मेरा जवाब देख सकते हैं। –

उत्तर

12

हैशटेबल एक्सएमएल को क्रमबद्धता का समर्थन नहीं करता है और न ही मैं एक साधारण स्ट्रिंग पर विश्वास करता हूं। जब आप सेटिंग्स.सेटिंग फ़ाइल और संबंधित ऑटो-जेनरेटेड क्लास का उपयोग करते हैं तो ये दो क्रमिक विकल्प उपलब्ध होते हैं।

हालांकि यदि आप स्वयं द्वारा अपनी सेटिंग्स कक्षा बनाते हैं और 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> 

कस्टम सेटिंग कक्षा मैन्युअल बनाया:

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

अद्यतन: यह निम्न फ़ाइलों के साथ एक सांत्वना अनुप्रयोग है यदि आप एक मानव पढ़ना चाहते हैं डेटा का सक्षम प्रतिनिधित्व, जिस दृष्टिकोण का आप उपयोग कर रहे हैं वह उचित लगता है। फिर भी आप एक अलग दृष्टिकोण का प्रयास कर सकते हैं जो स्ट्रिंग (एक्सएमएल) और स्ट्रिंग (एक्सएमएल) से कनवर्ट करने के तर्क को बेहतर ढंग से समाहित करता है।

यह दृष्टिकोण आपको कस्टम सेटिंग क्लास उत्पन्न करने या App.config के साथ गड़बड़ करने की आवश्यकता को हटाने के लिए सेटिंग्स.सेटिंग फ़ाइल के लिए आईडीई समर्थन का उपयोग करने की अनुमति देता है।

आपको केवल एक कस्टम क्लास को लागू करने की आवश्यकता है जो आपके डेटा को रखेगा, मेरे उदाहरण में मैं इस वर्ग को स्ट्रिंग डिक्शनरी से प्राप्त करूंगा और 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 क्लास को अपनी सेटिंग्स के डेटा प्रकार के रूप में उपयोग करने की आवश्यकता है। विजुअल स्टूडियो के कारण उपयोगकर्ता सेटिंग के लिए उपलब्ध डेटा प्रकारों में उपयोगकर्ता कक्षाओं को प्रदर्शित नहीं करने के कारण आपको एक बार वर्कअराउंड करने की आवश्यकता होती है जिसमें XML संपादक (राइट-क्लिक और ओपन चौड़ाई) के साथ सेटिंग्स.सेटिंग फ़ाइल खोलने और मैन्युअल रूप से निर्दिष्ट करने की आवश्यकता होती है। MyStringDictionary का पूरा नाम के रूप में उपयोगकर्ता सेटिंग का प्रकार।

उम्मीद है कि इससे मदद मिलती है।

+0

यह अब बहुत धन्यवाद काम करता है। मैंने इस समस्या का एक नया समाधान भी जोड़ा है। तुम उसके बारे में क्या सोचते हो? कोई अनुकूलन सुझाव? – Houman

+0

मेरे अपडेट की जांच करें ... –

+0

बहुत बहुत धन्यवाद। यह भी काम किया। अब हमारे पास समस्या के तीन समाधान हैं। : ओ) – Houman

संबंधित मुद्दे