অভিধান সদস্যযুক্ত ক্লাস সিরিয়াল করুন


144

আমার আগের সমস্যাটি প্রসারিত করে , আমি সিদ্ধান্ত নিয়েছি (ডি) আমার কনফিগারেশন ফাইল শ্রেণিকে সিরিয়ালাইজ করার সিদ্ধান্ত নিয়েছে যা দুর্দান্ত কাজ করেছে।

আমি এখন ম্যাপ (কী ড্রাইভ লেটার হয়, মান নেটওয়ার্কের পথ) এবং ব্যবহার চেষ্টা করেছি ড্রাইভ বর্ণের একটি মিশুক অ্যারে সঞ্চয় করতে চান Dictionary, HybridDictionaryএবং Hashtableএই জন্য কিন্তু আমি সবসময় নিম্নলিখিত ত্রুটির যখন কলিং পেতে ConfigFile.Load()বা ConfigFile.Save():

'App.ConfigFile' টাইপ প্রতিবিম্বিত করতে একটি ত্রুটি হয়েছিল। [স্নিপ] সিস্টেম.নাটসপোর্টড এক্সসেপশন: সদস্য অ্যাপটি ক্রমিকায়িত করা যায় না on কনফিগফিল.ম্যাপডড্রাইভ [স্নিপ]

আমি ডিকোরিজ এবং হ্যাশ টেবিল যা পড়েছি তা থেকে সিরিয়ালাইজ করা যেতে পারে, তবে আমি কী ভুল করছি?

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

উত্তর:


77

আপনি কোনও ক্লাস সিরিয়ালাইজ করতে পারবেন না যা আইডিকোরিয়াস প্রয়োগ করে। এই লিঙ্কটি দেখুন

প্রশ্ন: আমি কেন হ্যাশ টেবিল সিরিয়াল করতে পারি না?

উত্তর: এক্সএমএলসিরাইজার আইডোরিয়াস ইন্টারফেস প্রয়োগের ক্লাসগুলি প্রক্রিয়া করতে পারে না। এটি আংশিক সময়সূচী বাধার কারণে এবং আংশিকভাবে XSD টাইপ সিস্টেমে কোনও হ্যাশটেবলের কোনও অংশ নেই বলে এই কারণে হয়েছিল। একমাত্র সমাধান হ'ল একটি কাস্টম হ্যাশটেবল বাস্তবায়ন যা আইডোরিয়াস ইন্টারফেস বাস্তবায়ন করে না।

সুতরাং আমি মনে করি এর জন্য আপনার অভিধানের নিজস্ব সংস্করণ তৈরি করা দরকার। এই অন্যান্য প্রশ্ন পরীক্ষা করুন ।


4
DataContractSerializerক্লাসটি কী তা করতে পারে তা ভাবছেন । শুধু আউটপুটটি কিছুটা কুৎসিত।
rekire

186

পল ওয়েল্টারের ওয়েবলগে একটি সমাধান রয়েছে - এক্সএমএল সিরিয়ালাইজেবল জেনেরিক অভিধান

কোনও কারণে, .NET 2.0 এ জেনেরিক অভিধানটি এক্সএমএল সিরিয়ালযোগ্য নয়। নিম্নলিখিত কোড স্নিপেট একটি এক্সএমএল সিরিয়ালযোগ্য জেনেরিক অভিধান। আইএক্সএমএল সিরিয়ালাইজযোগ্য ইন্টারফেস প্রয়োগ করে অভিধানটি সিরিয়ালযোগ্য able

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
}

16
+1 টি। আরে, স্ট্যাক ওভারফ্লোতে কেন একটি অনুলিপি কোড বোতাম নেই? হুম? এই কোডটি অনুলিপি মূল্যবান!
টুডমো

1
+1 চমত্কার উত্তর। বাছাই করা তালিকার পক্ষেও কাজ করে, "সিরিয়ালাইজিবল ডিকোরিয়ালিটি" "সেরিয়ালাইজেবলসোর্টলিস্ট" এবং "অভিধান <টিকি, টিভিলু>" "" সোর্টার্ডলিস্ট <টি কে, টিভিয়াল>> এ পরিবর্তিত হয়েছে।
কেডমুররে

1
+1 এবং একটি পরামর্শ। যখন সিরিয়ালিজেবলড অভিধানে একাধিক উপাদান থাকে, তখন ব্যতিক্রম নিক্ষেপ করা হয় ... ReadXML () এবং WritXML () ReadStartElement ("আইটেম") সরানোর জন্য পরিবর্তন করা উচিত; এবং WritStartElement ("আইটেম"); এবং এর সাথে সম্পর্কিত ReadEndElement () এবং WritEndElement () লুপের বাইরে।
এমএনএস

1
তার মানে কি পরবর্তী ফ্রেমওয়ার্কগুলিতে আইডিকোরিয়ালটি সিরিয়ালযোগ্য?
থমাস

1
অভিধানটি স্টোর করে বলুন, stringমান বলুন, তবে এই প্রয়োগটি কার্যকর হবে InvalidOperationExceptionতবে আপনি যদি কাস্টম অবজেক্টস বা স্ট্রিং অ্যারেগুলি সংরক্ষণ করার চেষ্টা করেন তবে এটি একটি অপ্রত্যাশিত মোড়কের উপাদান উল্লেখ করে ডিসরিয়ালাইজেশনটিকে নিক্ষেপ করবে। ( আমি যে সমস্যার মুখোমুখি হয়েছি তার উদাহরণের জন্য আমার প্রশ্ন দেখুন ))
ক্রিস্টোফার কাইল হার্টন

57

পরিবর্তে XmlSerializerআপনি ব্যবহার করতে পারেন System.Runtime.Serialization.DataContractSerializer। এটি অভিধানগুলি এবং ইন্টারফেসগুলিকে কোনও ঘাম না দিয়ে সিরিয়ালাইজ করতে পারে।

এখানে একটি সম্পূর্ণ উদাহরণের একটি লিঙ্ক, http://theburningmonk.com/2010/05/net-tips-xML-serialize-or-deserialize-d অভিধান-in-csharp/


2
সেরা উত্তর, হাত ডাউন।
ডিডব্লিউরল্যান্ডস

সম্মত, এটি সেরা উত্তর। পরিষ্কার, সরল এবং DRY (নিজেকে পুনরাবৃত্তি করবেন না)।
নোলোনার

ডেটা কন্ট্রাক্টরিশায়ালাইজের সমস্যাটি হ'ল এটি বর্ণানুক্রমিক ক্রমে সিরিয়ালাইজ করে এবং ডিসরিয়ালাইজড করে তাই যদি আপনি কোনও কিছুকে ভুল ক্রমে deserialize করার চেষ্টা করেন তবে এটি আপনার বস্তুর নাল বৈশিষ্ট্যের সাথে নিঃশব্দে ব্যর্থ হবে
সুপারজুগি

14

সিরিয়ালাইজেশন সারোগেট তৈরি করুন।

উদাহরণস্বরূপ, আপনার অভিধানের ধরণের পাবলিক সম্পত্তি সহ একটি শ্রেণি রয়েছে।

এই ধরণের এক্সএমএল সিরিয়ালাইজেশন সমর্থন করতে, জেনেরিক কী-মান শ্রেণি তৈরি করুন:

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

আপনার আসল সম্পত্তিতে একটি এক্সএমএল উপেক্ষা যুক্ত করুন:

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

অ্যারে টাইপের এমন একটি সার্বজনীন সম্পত্তি প্রকাশ করুন, যা সিরিয়ালাইজেবলকিভ্যালু দৃষ্টান্তগুলির একটি অ্যারে ধারণ করে, যা অনুসন্ধানশ্রেণীর বৈশিষ্ট্যগুলিকে সিরিয়ালাইজ এবং ডিসাইরিয়ালাইজ করতে ব্যবহৃত হয়:

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

আমি এটি পছন্দ করি কারণ এটি অভিধান সদস্য থেকে ক্রমিকায়নটি ডিউপল করে। আমি যদি সিরিয়ালাইজেশন ক্ষমতাগুলি যুক্ত করতে চেয়েছিলাম এমন একটি ভারী ব্যবহৃত ক্লাস থাকি, তবে অভিধানটি মোড়ানো উত্তরাধিকারসূত্রে প্রাপ্ত ধরণের সাথে বিরতি সৃষ্টি করতে পারে।
ভোটকফি

এটি প্রয়োগকারী যে কোনও ব্যক্তির জন্য একটি সতর্কতার শব্দ: আপনি যদি নিজের সরগেট সম্পত্তিকে তালিকা (বা অন্য কোনও সংগ্রহ ) বানানোর চেষ্টা করেন , এক্সএমএল সিরিয়ালাইজার সেটটারটিকে কল করবে না (পরিবর্তে এটি গেটরকে কল করে এবং ফিরে আসা তালিকায় যোগ করার চেষ্টা করবে, যা অবশ্যই আপনি চান তা নয়)। এই প্যাটার্নটির জন্য অ্যারেটিতে লেগে থাকুন।
ফ্রেসটিল

9

আপনার জাসন.নেট অন্বেষণ করা উচিত, এটি ব্যবহার করা বেশ সহজ এবং জেসন অবজেক্টগুলিকে সরাসরি অভিধানে ডিসেরায়ালাইজ করার অনুমতি দেয়।

james_newtonking

উদাহরণ:

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

6

ডিকশনারি এবং হ্যাশ টেবিলগুলি সিরিয়ালযোগ্য নয় XmlSerializer। সুতরাং আপনি এগুলি সরাসরি ব্যবহার করতে পারবেন না। XmlIgnoreসিরিয়ালাইজার থেকে সেই বৈশিষ্ট্যগুলি আড়াল করার জন্য বৈশিষ্ট্যটি ব্যবহার করা এবং সিরিয়ালাইজযোগ্য কী-মান জোড়ার তালিকার মাধ্যমে তাদের প্রকাশ করা হবে A

পিএস: একটি নির্মাণ XmlSerializerকরা খুব ব্যয়বহুল, তাই এটি পুনরায় ব্যবহার করতে সক্ষম হওয়ার কোনও সুযোগ থাকলে সর্বদা এটি ক্যাশে করুন।


4

আমি একটি সিরিয়ালাইজডডিয়েশনারি ক্লাস চাইছিলাম যা কী / মানের জন্য এক্সএমএল বৈশিষ্ট্যগুলি ব্যবহার করে যাতে আমি পল ওয়েলটারের ক্লাসটি গ্রহণ করেছি।

এটি এক্সএমএল তৈরি করে:

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

কোড:

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

ইউনিট পরীক্ষা:

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

1
দেখতে দুর্দান্ত তবে এটি একটি খালি অভিধানে ব্যর্থ। আপনার পাঠক দরকার the রিডএক্সএমএল পদ্ধতিতে আইএসপিটিএলমেন্ট পরীক্ষা।
অ্যান্টনিভিও

2

অভিধান শ্রেণি ইসরায়েজযোগ্য কার্যকর করে। ক্লাস অভিধান সংজ্ঞা নীচে দেওয়া।

[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  

আমি মনে করি না যে সমস্যা। নীচের লিঙ্কটি দেখুন, যা বলেছে যে আপনার যদি অন্য কোনও ডেটা টাইপ থাকে যা সিরিয়ালাইজযোগ্য নয় তবে অভিধানটি সিরিয়ালীকৃত হবে না। http://forums.asp.net/t/1734187.aspx?Is+Dictionary+serializable+


সর্বশেষতম সংস্করণগুলিতে এটি সত্য, কিন্তু নেট 2 এ, অভিধানটি আজও সিরিয়ালযোগ্য নয়। .NET 3.5 কে লক্ষ্য করে একটি প্রকল্পের মাধ্যমে আমি এটি আজই নিশ্চিত করেছি, এটিই আমি এই থ্রেডটি পেয়েছি।
ব্রুস

2

আপনি এক্সটেন্ডেডএক্সএমএলসিরাইজার ব্যবহার করতে পারেন । আপনার যদি ক্লাস থাকে:

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

এবং এই শ্রেণীর উদাহরণ তৈরি করুন:

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");

আপনি এক্সটেন্ডেড এক্সএমএল সিরিয়ালাইজার ব্যবহার করে এই বিষয়টিকে সিরিয়ালাইজ করতে পারেন:

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

আউটপুট এক্সএমএল দেখতে পাবেন:

<?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>

আপনি নুগেট থেকে এক্সটেন্ডডএক্সএমএলসিরাইজার ইনস্টল করতে পারেন বা নিম্নলিখিত কমান্ডটি চালাতে পারেন :

Install-Package ExtendedXmlSerializer

এখানে অনলাইন উদাহরণ


0

এই নিবন্ধটি ঠিক কীভাবে এটি পরিচালনা করবেন তা ব্যাখ্যা করে: আমি কীভাবে করব ... যখন অ্যাপ্লিকেশনটির প্রয়োজন হয় তখন সি # তে একটি হ্যাশ টেবিলটি সিরিয়াল করুন?

আমি আশা করি এই সহায়ক


কেবলমাত্র লিঙ্ক-উত্তর বিট পচনের সাপেক্ষে, এবং প্রয়োজনীয় বিবরণের সাথে উত্তর বডিতেই সংক্ষিপ্ত করা উচিত।
ক্রিস্টোফার কাইল হরটন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.