Helpex - Trao đổi & giúp đỡ Đăng nhập
146

Mở rộng vấn đề trước đó của tôi , tôi đã quyết định (de) tuần tự hóa lớp tệp cấu hình của mình, điều này đã hoạt động tốt.

Bây giờ tôi muốn để lưu trữ một mảng kết hợp của các chữ cái ổ đĩa để lập bản đồ (Điều quan trọng là các ký tự ổ đĩa, giá trị là con đường mạng) và đã cố gắng sử dụng Dictionary, HybridDictionaryHashtablecho điều này nhưng tôi luôn luôn nhận được lỗi sau khi gọi ConfigFile.Load()hoặc ConfigFile.Save():

Đã xảy ra lỗi khi phản ánh loại 'App.ConfigFile'. [snip] System.NotSupportedException: Không thể tuần tự hóa App.Configfile.mappedDrives của thành viên [snip]

Từ những gì tôi đã đọc Từ điển và HashTables có thể được đăng nhiều kỳ, vậy tôi đang làm gì sai?

[XmlRoot(ElementName="Config")]
public class ConfigFile
{
    public String guiPath { get; set; }
    public string configPath { get; set; }
    public Dictionary<string, string> mappedDrives = new Dictionary<string, string>();

    public Boolean Save(String filename)
    {
        using(var filestream = File.Open(filename, FileMode.OpenOrCreate,FileAccess.ReadWrite))
        {
            try
            {
                var serializer = new XmlSerializer(typeof(ConfigFile));
                serializer.Serialize(filestream, this);
                return true;
            } catch(Exception e) {
                MessageBox.Show(e.Message);
                return false;
            }
        }
    }

    public void addDrive(string drvLetter, string path)
    {
        this.mappedDrives.Add(drvLetter, path);
    }

    public static ConfigFile Load(string filename)
    {
        using (var filestream = File.Open(filename, FileMode.Open, FileAccess.Read))
        {
            try
            {
                var serializer = new XmlSerializer(typeof(ConfigFile));
                return (ConfigFile)serializer.Deserialize(filestream);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + ex.ToString());
                return new ConfigFile();
            }
        }
    }
}
146 hữu ích 0 bình luận 164k xem chia sẻ
10 trả lời 10
77

Bạn không thể tuần tự hóa một lớp triển khai IDictionary. Kiểm tra liên kết này .

H: Tại sao tôi không thể tuần tự hóa các thẻ bắt đầu bằng #?

A: XmlSerializer không thể xử lý các lớp triển khai giao diện IDictionary. Điều này một phần là do các hạn chế về lịch trình và một phần là do bảng băm không có đối tác trong hệ thống kiểu XSD. Giải pháp duy nhất là triển khai bảng băm tùy chỉnh không triển khai giao diện IDictionary.

Vì vậy, tôi nghĩ bạn cần tạo phiên bản Từ điển của riêng mình cho việc này. Kiểm tra câu hỏi khác này .

77 hữu ích 1 bình luận chia sẻ
188

Có một giải pháp tại Weblog của Paul Welter - Từ điển chung có thể tuần tự hóa XML

Vì một số lý do, Từ điển chung trong .net 2.0 không thể tuần tự hóa XML. Đoạn mã sau là một từ điển chung có thể tuần tự hóa xml. Từ điển có thể tuần tự hóa bằng cách triển khai giao diện IXmlSerializable.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue>
    : Dictionary<TKey, TValue>, IXmlSerializable
{
    public SerializableDictionary() { }
    public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }
    public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }
    public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }
    public SerializableDictionary(int capacity) : base(capacity) { }
    public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }

    #region IXmlSerializable Members
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        bool wasEmpty = reader.IsEmptyElement;
        reader.Read();

        if (wasEmpty)
            return;

        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            reader.ReadStartElement("item");

            reader.ReadStartElement("key");
            TKey key = (TKey)keySerializer.Deserialize(reader);
            reader.ReadEndElement();

            reader.ReadStartElement("value");
            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();

            this.Add(key, value);

            reader.ReadEndElement();
            reader.MoveToContent();
        }
        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement("item");

            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

            writer.WriteStartElement("value");
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }
    #endregion
}
188 hữu ích 5 bình luận chia sẻ
58

Thay vì sử dụng XmlSerializerbạn có thể sử dụng a System.Runtime.Serialization.DataContractSerializer. Điều này có thể tuần tự hóa các từ điển và giao diện mà không tốn kém.

Đây là liên kết đến một ví dụ đầy đủ, http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/

58 hữu ích 1 bình luận chia sẻ
14

Tạo đại diện tuần tự hóa.

Ví dụ, bạn có một lớp có thuộc tính công cộng kiểu Từ điển.

Để hỗ trợ tuần tự hóa Xml kiểu này, hãy tạo một lớp khóa-giá trị chung:

public class SerializeableKeyValue<T1,T2>
{
    public T1 Key { get; set; }
    public T2 Value { get; set; }
}

Thêm thuộc tính XmlIgnore vào thuộc tính ban đầu của bạn:

    [XmlIgnore]
    public Dictionary<int, string> SearchCategories { get; set; }

Hiển thị một thuộc tính công khai của kiểu mảng, chứa một mảng các thể hiện SerializableKeyValue, được sử dụng để tuần tự hóa và giải mã hóa vào thuộc tính SearchCategories:

    public SerializeableKeyValue<int, string>[] SearchCategoriesSerializable
    {
        get
        {
            var list = new List<SerializeableKeyValue<int, string>>();
            if (SearchCategories != null)
            {
                list.AddRange(SearchCategories.Keys.Select(key => new SerializeableKeyValue<int, string>() {Key = key, Value = SearchCategories[key]}));
            }
            return list.ToArray();
        }
        set
        {
            SearchCategories = new Dictionary<int, string>();
            foreach (var item in value)
            {
                SearchCategories.Add( item.Key, item.Value );
            }
        }
    }
14 hữu ích 2 bình luận chia sẻ
9

Bạn nên khám phá Json.Net, khá dễ sử dụng và cho phép các đối tượng Json được deserialized trong Từ điển trực tiếp.

james_newtonking

thí dụ:

string json = @"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json); 
Console.WriteLine(values.Count);
// 2
Console.WriteLine(values["key1"]);
// value1
9 hữu ích 0 bình luận chia sẻ
6

Từ điển và Bảng băm không thể tuần tự hóa với XmlSerializer. Do đó bạn không thể sử dụng chúng trực tiếp. Một giải pháp khác sẽ là sử dụng XmlIgnorethuộc tính để ẩn các thuộc tính đó khỏi bộ tuần tự hóa và hiển thị chúng qua danh sách các cặp khóa-giá trị có thể tuần tự hóa.

Tái bút: việc xây dựng một XmlSerializerrất tốn kém, vì vậy hãy luôn cache nó nếu có cơ hội sử dụng lại nó.

6 hữu ích 0 bình luận chia sẻ
4

Tôi muốn một lớp SerializableDictionary sử dụng các thuộc tính xml cho khóa / giá trị nên tôi đã điều chỉnh lớp của Paul Welter.

Điều này tạo ra xml như:

<Dictionary>
  <Item Key="Grass" Value="Green" />
  <Item Key="Snow" Value="White" />
  <Item Key="Sky" Value="Blue" />
</Dictionary>"

Mã:

using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace DataTypes {
    [XmlRoot("Dictionary")]
    public class SerializableDictionary<TKey, TValue>
        : Dictionary<TKey, TValue>, IXmlSerializable {
        #region IXmlSerializable Members
        public System.Xml.Schema.XmlSchema GetSchema() {
            return null;
        }

        public void ReadXml(XmlReader reader) {
            XDocument doc = null;
            using (XmlReader subtreeReader = reader.ReadSubtree()) {
                doc = XDocument.Load(subtreeReader);
            }
            XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
            foreach (XElement item in doc.Descendants(XName.Get("Item"))) {
                using(XmlReader itemReader =  item.CreateReader()) {
                    var kvp = serializer.Deserialize(itemReader) as SerializableKeyValuePair<TKey, TValue>;
                    this.Add(kvp.Key, kvp.Value);
                }
            }
            reader.ReadEndElement();
        }

        public void WriteXml(System.Xml.XmlWriter writer) {
            XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            foreach (TKey key in this.Keys) {
                TValue value = this[key];
                var kvp = new SerializableKeyValuePair<TKey, TValue>(key, value);
                serializer.Serialize(writer, kvp, ns);
            }
        }
        #endregion

        [XmlRoot("Item")]
        public class SerializableKeyValuePair<TKey, TValue> {
            [XmlAttribute("Key")]
            public TKey Key;

            [XmlAttribute("Value")]
            public TValue Value;

            /// <summary>
            /// Default constructor
            /// </summary>
            public SerializableKeyValuePair() { }
        public SerializableKeyValuePair (TKey key, TValue value) {
            Key = key;
            Value = value;
        }
    }
}
}

Kiểm tra đơn vị:

using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DataTypes {
    [TestClass]
    public class SerializableDictionaryTests {
        [TestMethod]
        public void TestStringStringDict() {
            var dict = new SerializableDictionary<string, string>();
            dict.Add("Grass", "Green");
            dict.Add("Snow", "White");
            dict.Add("Sky", "Blue");
            dict.Add("Tomato", "Red");
            dict.Add("Coal", "Black");
            dict.Add("Mud", "Brown");

            var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
            using (var stream = new MemoryStream()) {
                // Load memory stream with this objects xml representation
                XmlWriter xmlWriter = null;
                try {
                    xmlWriter = XmlWriter.Create(stream);
                    serializer.Serialize(xmlWriter, dict);
                } finally {
                    xmlWriter.Close();
                }

                // Rewind
                stream.Seek(0, SeekOrigin.Begin);

                XDocument doc = XDocument.Load(stream);
                Assert.AreEqual("Dictionary", doc.Root.Name);
                Assert.AreEqual(dict.Count, doc.Root.Descendants().Count());

                // Rewind
                stream.Seek(0, SeekOrigin.Begin);
                var outDict = serializer.Deserialize(stream) as SerializableDictionary<string, string>;
                Assert.AreEqual(dict["Grass"], outDict["Grass"]);
                Assert.AreEqual(dict["Snow"], outDict["Snow"]);
                Assert.AreEqual(dict["Sky"], outDict["Sky"]);
            }
        }

        [TestMethod]
        public void TestIntIntDict() {
            var dict = new SerializableDictionary<int, int>();
            dict.Add(4, 7);
            dict.Add(5, 9);
            dict.Add(7, 8);

            var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
            using (var stream = new MemoryStream()) {
                // Load memory stream with this objects xml representation
                XmlWriter xmlWriter = null;
                try {
                    xmlWriter = XmlWriter.Create(stream);
                    serializer.Serialize(xmlWriter, dict);
                } finally {
                    xmlWriter.Close();
                }

                // Rewind
                stream.Seek(0, SeekOrigin.Begin);

                XDocument doc = XDocument.Load(stream);
                Assert.AreEqual("Dictionary", doc.Root.Name);
                Assert.AreEqual(3, doc.Root.Descendants().Count());

                // Rewind
                stream.Seek(0, SeekOrigin.Begin);
                var outDict = serializer.Deserialize(stream) as SerializableDictionary<int, int>;
                Assert.AreEqual(dict[4], outDict[4]);
                Assert.AreEqual(dict[5], outDict[5]);
                Assert.AreEqual(dict[7], outDict[7]);
            }
        }
    }
}
4 hữu ích 1 bình luận chia sẻ
2

lớp Dictionary triển khai ISerializable. Định nghĩa của Class Dictionary được đưa ra dưới đây.

[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
[System.Runtime.InteropServices.ComVisible(false)]
public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback  

Tôi không nghĩ đó là vấn đề. hãy tham khảo liên kết dưới đây, cho biết rằng nếu bạn đang có bất kỳ kiểu dữ liệu nào khác không thể tuần tự hóa thì Từ điển sẽ không được tuần tự hóa. http://forums.asp.net/t/1734187.aspx?Is+Dictionary+serializable+

2 hữu ích 1 bình luận chia sẻ
2

Bạn có thể sử dụng ExtendedXmlSerializer . Nếu bạn có một lớp học:

public class ConfigFile
{
    public String guiPath { get; set; }
    public string configPath { get; set; }
    public Dictionary<string, string> mappedDrives {get;set;} 

    public ConfigFile()
    {
        mappedDrives = new Dictionary<string, string>();
    }
}

và tạo phiên bản của lớp này:

ConfigFile config = new ConfigFile();
config.guiPath = "guiPath";
config.configPath = "configPath";
config.mappedDrives.Add("Mouse", "Logitech MX Master");
config.mappedDrives.Add("keyboard", "Microsoft Natural Ergonomic Keyboard 4000");

Bạn có thể tuần tự hóa đối tượng này bằng ExtendedXmlSerializer:

ExtendedXmlSerializer serializer = new ExtendedXmlSerializer();
var xml = serializer.Serialize(config);

Xml đầu ra sẽ giống như sau:

<?xml version="1.0" encoding="utf-8"?>
<ConfigFile type="Program+ConfigFile">
    <guiPath>guiPath</guiPath>
    <configPath>configPath</configPath>
    <mappedDrives>
        <Item>
            <Key>Mouse</Key>
            <Value>Logitech MX Master</Value>
        </Item>
        <Item>
            <Key>keyboard</Key>
            <Value>Microsoft Natural Ergonomic Keyboard 4000</Value>
        </Item>
    </mappedDrives>
</ConfigFile>

Bạn có thể cài đặt ExtendedXmlSerializer từ nuget hoặc chạy lệnh sau:

Install-Package ExtendedXmlSerializer

Đây là ví dụ trực tuyến

2 hữu ích 0 bình luận chia sẻ
0

Bài viết này giải thích chính xác cách xử lý điều này: Làm cách nào để ... Tuần tự hóa bảng băm trong C # khi ứng dụng yêu cầu?

Tôi hy vọng điều này là hữu ích

0 hữu ích 1 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ c# .net serialization dictionary , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading