2009-05-28 30 views
30

Tôi có một từ điển chuỗi mà tôi muốn người dùng có thể thêm/xóa thông tin rồi lưu trữ thông tin cho họ để họ có thể truy cập vào lần tiếp theo khi chương trình khởi động lạiTừ điển cửa hàng <string, string> trong các cài đặt ứng dụng

Tôi chưa rõ cách tôi có thể lưu trữ từ điển làm cài đặt. Tôi thấy rằng trong system.collections.special có một điều được gọi là một stringdictionary nhưng ive đọc rằng SD là lỗi thời và không nên được sử dụng.

cũng trong tương lai tôi có thể có nhu cầu để lưu trữ một cuốn từ điển đó không phải là chuỗi chỉ (int string)

làm thế nào bạn sẽ lưu trữ một cuốn từ điển trong các tập tin cài đặt cho một ứng dụng net?

+0

Liên quan: http://stackoverflow.com/questions/2890271/how-to-save-a-liststring-on-settings-default – BrunoLM

Trả lời

13

Câu trả lời đơn giản nhất là sử dụng hàng & dấu phân tách cột để chuyển từ điển của bạn thành một chuỗi. Sau đó, bạn chỉ cần lưu trữ 1 chuỗi trong tệp cài đặt.

+5

Ý tưởng hay - sử dụng một thứ gì đó giống như JSON serialization để làm cho quá trình này tương đối không đau. –

+0

bạn có thể tập trung vào điều đó một chút không? – Crash893

+1

Tuần tự hóa JSON có dạng {"đối tượng": {"khóa": "giá trị", "khóa": "giá trị"}} –

3

Khác với việc làm một cái gì đó như David's suggests, tôi sẽ xem xét lưu trữ thay thế cho Từ điển. Cuối cùng, đối tượng Settings sẽ nối tiếp vào đĩa.

1

Bạn có thể tạo lớp tùy chỉnh hiển thị Từ điển dưới dạng thuộc tính công khai. Sau đó, bạn có thể chỉ định loại tùy chỉnh này làm loại cho cài đặt của mình.

Edit:

Tôi vừa đọc rằng, đối với một số lý do, một cuốn từ điển chung không thể XML-đăng, vì vậy giải pháp của tôi có thể sẽ không làm việc (tôi đã không kiểm tra nó mặc dù ...). Đó là lạ, bởi vì một danh sách chung chung có thể được serialized mà không có bất kỳ vấn đề.

Bạn vẫn có thể tạo lớp tùy chỉnh có thể được đặt làm cài đặt người dùng, nhưng bạn sẽ cần phải có danh sách được hiển thị dưới dạng thuộc tính thay vì từ điển.

+0

Tôi không chắc chắn tôi làm theo. tạo một lớp có chứa một từ điển sau đó lưu lớp đó? – Crash893

+0

Chính xác, nhưng vì từ điển chung không thể tuần tự hóa (xem chỉnh sửa) nên nó sẽ cần phải là danh sách thay thế. –

3

Bạn đã xem xét sử dụng XML để lưu trữ từ điển của mình chưa? Điều đó sẽ cung cấp một số tiền nhất định của khả năng mở rộng nếu trong tương lai bạn quyết định bạn muốn có thể lưu trữ các loại từ điển khác. Bạn có thể làm điều gì đó như:

<dictionary> 
    <entry key="myKey"> 
     [whatever data you like] 
    </entry> 
</dictionary> 

Có thể quá mức cần thiết, nhưng bạn cũng sẵn sàng trong trường hợp bạn muốn lưu trữ dữ liệu phức tạp hơn, như đối tượng tùy chỉnh.

1

Bạn cũng có thể sử dụng System.Collections.Specialized.StringCollection bằng cách đặt khóa trên chỉ mục và giá trị trên chỉ mục lẻ.

/// <summary> 
/// Emulate a Dictionary (Serialization pb) 
/// </summary> 
private static string getValue(System.Collections.Specialized.StringCollection list, string key) 
{ 
    for (int i = 0; i * 2 < list.Count; i++) 
    { 
     if (list[i] == key) 
     { 
      return list[i + 1]; 
     } 
    } 
    return null; 
} 

/// <summary> 
/// Emulate a Dictionary (Serialization pb) 
/// </summary>  
private static void setValue(System.Collections.Specialized.StringCollection list, string key, string value) 
{ 
    for (int i = 0; i * 2 < list.Count; i++) 
    { 
     if (list[i] == key) 
     { 
      list[i + 1] = value; 
      return; 
     } 
    } 
    list.Add(key); 
    list.Add(value); 
} 
1

Chỉnh sửa: Điều này sẽ trả về giá trị Hashtable (vì lý do gì, mặc dù là 'DictionarySectionHandler'). Tuy nhiên, vì Hashtables và Dictionaries rất giống nhau, nên nó không phải là một vấn đề lớn (mặc dù tôi nhận ra Từ điển mới hơn, được tham số hóa, v.v.), tôi sẽ ưu tiên dicitonaries, nhưng đây là những gì .NET cho chúng ta).


Câu trả lời hay nhất mà tôi vừa tìm thấy là here. Nó trả về một bộ sưu tập an toàn không có bất kỳ mã nào trong mã để chuyển đổi nó, và bạn tạo một bộ sưu tập rõ ràng (và đơn giản) trong tệp .config của bạn. Tôi đang sử dụng này và nó khá thẳng về phía trước cho bất kỳ lập trình viên trong tương lai (bao gồm cả chính mình). Nó cho phép gõ mạnh mẽ hơn và linh hoạt hơn, mà không cần phân tích cú pháp quá phức tạp và không cần thiết.

1

Bạn có thể lưu trữ StringCollection.Nó tương tự như to this solution.

Tôi đã thực hiện 2 phương pháp mở rộng để chuyển đổi giữa StringCollectionDictionary. Đây là cách dễ nhất tôi có thể nghĩ đến.

public static class Extender 
{ 
    public static Dictionary<string, string> ToDictionary(this StringCollection sc) 
    { 
     if (sc.Count % 2 != 0) throw new InvalidDataException("Broken dictionary"); 

     var dic = new Dictionary<string, string>(); 
     for (var i = 0; i < sc.Count; i += 2) 
     { 
      dic.Add(sc[i], sc[i + 1]); 
     } 
     return dic; 
    } 

    public static StringCollection ToStringCollection(this Dictionary<string, string> dic) 
    { 
     var sc = new StringCollection(); 
     foreach (var d in dic) 
     { 
      sc.Add(d.Key); 
      sc.Add(d.Value); 
     } 
     return sc; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     //var sc = new StringCollection(); 
     //sc.Add("Key01"); 
     //sc.Add("Val01"); 
     //sc.Add("Key02"); 
     //sc.Add("Val02"); 

     var sc = Settings.Default.SC; 

     var dic = sc.ToDictionary(); 
     var sc2 = dic.ToStringCollection(); 

     Settings.Default.SC = sc2; 
     Settings.Default.Save(); 
    } 
} 
40

Bạn có thể sử dụng lớp này có nguồn gốc từ StringDictionary. Để có ích cho các thiết lập ứng dụng, nó thực hiện IXmlSerializable. Hoặc bạn có thể sử dụng cách tiếp cận tương tự để triển khai lớp XmlSerializable của riêng bạn.

public class SerializableStringDictionary : StringDictionary, IXmlSerializable 
{ 
    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     while (reader.Read() && 
      !(reader.NodeType == XmlNodeType.EndElement && reader.LocalName == this.GetType().Name)) 
     { 
      var name = reader["Name"]; 
      if (name == null) 
       throw new FormatException(); 

      var value = reader["Value"]; 
      this[name] = value; 
     } 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     foreach (DictionaryEntry entry in this) 
     { 
      writer.WriteStartElement("Pair"); 
      writer.WriteAttributeString("Name", (string)entry.Key); 
      writer.WriteAttributeString("Value", (string)entry.Value); 
      writer.WriteEndElement(); 
     } 
    } 
} 

Kết quả đoạn XML sẽ trông giống như:

... 
<setting name="PluginSettings" serializeAs="Xml"> 
    <value> 
     <SerializableStringDictionary> 
      <Pair Name="property1" Value="True" /> 
      <Pair Name="property2" Value="05/01/2011 0:00:00" /> 
     </SerializableStringDictionary> 
    </value> 
</setting> 
... 
+3

Tôi không biết tại sao câu trả lời này không được chấp nhận. Rất hữu ích, cảm ơn! – hazzik

+3

Làm việc cho tôi, nhưng tôi đã thêm câu lệnh 'this.Clear();' vào đầu phương thức ReadXml, để đảm bảo không có bất kỳ mục cũ nào trong từ điển. –

+0

Làm cách nào để mở rộng việc này sang từ điển chung? – Will

3

Nếu bạn không cần phải sử dụng thiết kế cài đặt hoặc chỉnh sửa cài đặt của bạn với một trình soạn thảo văn bản, bạn có thể tạo một lớp đơn giản có nguồn gốc từ ApplicationSettingsBase:

namespace MyNamespace 
{ 
    using System.Collections.Generic; 
    using System.Configuration; 

    /// <summary> 
    /// Persistent store for my parameters. 
    /// </summary> 
    public class MySettings : ApplicationSettingsBase 
    { 
     /// <summary> 
     /// The instance lock. 
     /// </summary> 
     private static readonly object InstanceLock = new object(); 

     /// <summary> 
     /// The instance. 
     /// </summary> 
     private static MySettings instance; 

     /// <summary> 
     /// Prevents a default instance of the <see cref="MySettings"/> class 
     /// from being created. 
     /// </summary> 
     private MySettings() 
     { 
      // don't need to do anything 
     } 

     /// <summary> 
     /// Gets the singleton. 
     /// </summary> 
     public static MySettings Instance 
     { 
      get 
      { 
       lock (InstanceLock) 
       { 
        if (instance == null) 
        { 
         instance = new MySettings(); 
        } 
       } 

       return instance; 
      } 
     } 

     /// <summary> 
     /// Gets or sets the parameters. 
     /// </summary> 
     [UserScopedSetting] 
     [SettingsSerializeAs(SettingsSerializeAs.Binary)] 
     public Dictionary<string, string> Parameters 
     { 
      get 
      { 
       return (Dictionary<string, string>)this["Parameters"]; 
      } 

      set 
      { 
       this["Parameters"] = value; 
      } 
     } 
    } 
} 

Bí quyết thực sự là [Cài đặtSerializeAs (SettingsSerializeAs.Binary)] thuộc tính. Hầu hết (tất cả?) Các lớp học có thể được đăng theo cách này, trong đó Cài đặtSerializeAs.String hoặc Cài đặtSerializeAs.Xml sẽ không hoạt động cho Từ điển.

Sử dụng này trong mã của bạn như bạn sẽ cài đặt bình thường:

// this code untested... 
MySettings.Instance.Parameters["foo"] = "bar"; 
MySettings.Instance.Parameters.Save(); 
MySettings.Instance.Parameters.Reload(); 
string bar; 
if (!MySettings.Instance.Parameters.TryGetValue("foo", out bar)) 
{ 
    throw new Exception("Foobar"); 
} 

Nếu bạn muốn từ điển để serialize vào một cái gì đó người dùng có thể chỉnh sửa, bạn phải xuất phát từ điển và chơi với TypeConverter (xem Using Custom Classes with Application Settings).

Các vấn đề liên quan