2009-11-21 5 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, 많은 감사 이진 솔루션입니다. 나는 그것을 꽤 재미 있다고 느낍니다. 바이너리로 직렬화 할 때의 단점은 더 이상 수동으로 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); 
     } 
+0

나는 방금 Hashtable을 사용자 설정으로 유지하면서 아무 문제도 감지하지 못했습니다. 아직 완료하지 않았다면 새로운 테스트 프로젝트에서 처음부터 다시 시도하십시오. –

+0

안녕하세요, 방금 다시 시도했습니다. 그것은 저장하고 응용 프로그램을 다시 시작한 후에도 Properties.Settings.Default.Setting은 null로 유지됩니다. 그것은 비록 문자열과 같은 다른 유형과 함께 작동합니다. 어떻게 작동 시켰어? 어떻게 든 솔루션을 게시 할 수 있습니까? – Houman

+0

나는 시험에서 성급했다. Hashtable은 기본 설정 클래스를 사용하는 응용 프로그램 실행간에 유지되지 않습니다. 그러나 Hashtable을 가지고 있고 수동 작업에 신경 쓸 필요가 없다면 내 대답을 확인할 수 있습니다. –

답변

12

Hashtable은 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> 

:

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)로 변환하는 논리를보다 잘 캡슐화하는 다른 접근 방식을 시도해 볼 수 있습니다.

이 방법을 사용하면 Custom.settings 클래스를 생성하거나 App.config를 사용하여 불필요한 작업을 제거하고 Settings.settings 파일에 대한 IDE 지원을 사용할 수 있습니다.

데이터를 보유 할 사용자 지정 클래스를 구현하기 만하면됩니다. 예를 들어 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 편집기 (Settings) 설정 파일을 열고 (마우스 오른쪽 버튼으로 클릭하고 너비 열기) 한 번에 해결 방법을 수행해야합니다. 사용자 설정의 형식을 MyStringDictionary의 전체 이름으로 지정합니다.

희망이 도움이됩니다.

+0

이것은 많은 감사를드립니다. 이 문제에 대한 새로운 해결책을 추가했습니다. 그것에 대해 어떻게 생각하세요? 어떤 최적화 제안? – Houman

+0

내 업데이트를 확인하십시오 ... –

+0

고마워요. 이것은 효과가 있었다. 이제 우리는 문제에 대한 세 가지 해결책을 가지고 있습니다. : o) – Houman

관련 문제