IXMLSerializable কার্যকর করার সঠিক উপায়?


153

কোনও প্রোগ্রামার একবার প্রয়োগ করার সিদ্ধান্ত নিলে এর প্রয়োগের IXmlSerializableজন্য নিয়ম এবং সর্বোত্তম অনুশীলনগুলি কী কী? আমি শুনেছি যে GetSchema()ফিরে আসা উচিত nullএবং ReadXmlফিরে আসার আগে পরবর্তী উপাদানটিতে চলে যাওয়া উচিত। এটা কি সত্য? এবং কী WriteXml- এটি কি বস্তুর জন্য একটি মূল উপাদান লিখতে হবে বা এটি ধারণা করা হয় যে ইতিমধ্যে মূল লেখা হয়েছে? শিশু অবজেক্টগুলিকে কীভাবে চিকিত্সা করা এবং লেখা উচিত?

আমার এখন যা আছে তার একটি নমুনা এখানে। আমি যেমন ভাল প্রতিক্রিয়া পেয়েছি তা আপডেট করব।

public class MyCalendar : IXmlSerializable
{
    private string _name;
    private bool _enabled;
    private Color _color;
    private List<MyEvent> _events = new List<MyEvent>();


    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader)
    {
        if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyCalendar")
        {
            _name    = reader["Name"];
            _enabled = Boolean.Parse(reader["Enabled"]);
            _color   = Color.FromArgb(Int32.Parse(reader["Color"]));

            if (reader.ReadToDescendant("MyEvent"))
            {
                while (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyEvent")
                {
                    MyEvent evt = new MyEvent();
                    evt.ReadXml(reader);
                    _events.Add(evt);
                }
            }
            reader.Read();
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("Name",    _name);
        writer.WriteAttributeString("Enabled", _enabled.ToString());
        writer.WriteAttributeString("Color",   _color.ToArgb().ToString());

        foreach (MyEvent evt in _events)
        {
            writer.WriteStartElement("MyEvent");
            evt.WriteXml(writer);
            writer.WriteEndElement();
        }
    }
}

public class MyEvent : IXmlSerializable
{
    private string _title;
    private DateTime _start;
    private DateTime _stop;


    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader)
    {
        if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyEvent")
        {
            _title = reader["Title"];
            _start = DateTime.FromBinary(Int64.Parse(reader["Start"]));
            _stop  = DateTime.FromBinary(Int64.Parse(reader["Stop"]));
            reader.Read();
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("Title", _title);
        writer.WriteAttributeString("Start", _start.ToBinary().ToString());
        writer.WriteAttributeString("Stop",  _stop.ToBinary().ToString());
    }
}

সংশ্লিষ্ট নমুনা এক্সএমএল

<MyCalendar Name="Master Plan" Enabled="True" Color="-14069085">
    <MyEvent Title="Write Code" Start="-8589241828854775808" Stop="-8589241756854775808" />
    <MyEvent Title="???" Start="-8589241828854775808" Stop="-8589241756854775808" />
    <MyEvent Title="Profit!" Start="-8589247048854775808" Stop="-8589246976854775808" />
</MyCalendar>

3
আপনি এই প্রশ্নের একটি এক্সএমএল নমুনা যোগ করতে পারেন? কোড সহ পড়তে এটি সহজ করে তুলবে। ধন্যবাদ!
ররি

আপনার এক্সএমএলে শেষ ইভেন্টের পরে এক্সএমএল মন্তব্য ইত্যাদির সাথে মোকাবিলা করার কী আছে। উদাহরণস্বরূপ, আপনি কি এমন কিছু দিয়ে ReadXML () পদ্ধতিটি শেষ করে শেষের উপাদানটি যা দেখেছেন তা পরীক্ষা করে? বর্তমানে এটি ধরে নেয় সর্বশেষ পড়ুন () এটি করে তবে এটি সর্বদা নাও হতে পারে।
ররি

7
@ ররি - নমুনা যুক্ত হয়েছে। আগের চেয়ে ভাল আর দেরি?
গ্রেগ

@ গ্রেগ গুড ইনফরমেশন। আপনি কি চাইবেন না যে ReadXML এবং WritXML ইনভেরিয়েন্ট সংস্কৃতি ব্যবহার করবে? আমি মনে করি যদি ব্যবহারকারী অন্য দেশে চলে যায় এবং তাদের অঞ্চল এবং ভাষা সেটিংস পরিবর্তন করে তবে আপনি সমস্যার মধ্যে পড়তে পারেন। সেক্ষেত্রে কোডটি সঠিকভাবে deserialize না করতে পারে। আমি পড়েছি সিরিয়ালাইজেশন করার সময় সর্বদা ইনভেরেন্ট সংস্কৃতি ব্যবহার করা একটি সেরা অনুশীলন
সর্বজনীন ওয়্যারলেস

উত্তর:


100

হ্যাঁ, গেটসচেমা () এর বাতিল হওয়া উচিত

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

উভয়ই পঠন এবং লেখার জন্য, অবজেক্ট উপাদানটি ইতিমধ্যে লিখিত হয়েছে, সুতরাং আপনাকে লেখায় কোনও বাহ্যিক উপাদান যুক্ত করার দরকার নেই। উদাহরণস্বরূপ, আপনি কেবল দুটিতে গুণাবলী পড়া / লিখতে শুরু করতে পারেন।

জন্য লেখ :

আপনি যে লিখনএক্সএমএল প্রয়োগ করেছেন সেটির জন্য বস্তুর XML উপস্থাপনা লেখা উচিত। ফ্রেমওয়ার্কটি একটি মোড়কের উপাদান লিখেছে এবং এটি শুরু হওয়ার পরে এক্সএমএল লেখককে অবস্থান দেয়। আপনার বাস্তবায়ন শিশু উপাদান সহ এর বিষয়বস্তু লিখতে পারে। ফ্রেমওয়ার্কটি পরে মোড়কের উপাদানটি বন্ধ করে।

এবং পড়ার জন্য :

ReadXML পদ্ধতিতে WritXML পদ্ধতি দ্বারা লিখিত তথ্য ব্যবহার করে অবশ্যই আপনার অবজেক্টটি পুনর্গঠন করতে হবে।

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

আমি সম্মতি জানাই যে এটি কিছুটা অস্পষ্ট, তবে এটি "র‍্যাপারের Read()শেষ-উপাদান ট্যাগটিতে আপনার কাজ" to


ইভেন্ট উপাদানগুলি লেখার এবং পড়া সম্পর্কে কী? এটি শুরুর উপাদানটি ম্যানুয়ালি লিখতে হাকশ বোধ করে। আমি মনে করি যে আমি প্রত্যেকে সন্তানের প্রতিটি উপাদান লিখতে লিখতে একটি এক্সএমএসআরশায়ালাইজার ব্যবহার করতে দেখেছি।
গ্রেগ

@Greg; হয় ব্যবহার ঠিক আছে ... হ্যাঁ, আপনার প্রয়োজন হলে আপনি নেস্টেড এক্সএমএলসিরিয়ালাইজার ব্যবহার করতে পারেন, তবে এটি একমাত্র বিকল্প নয়।
মার্ক গ্র্যাভেল

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

1
@ মার্কগ্রাভেল আমি জানি এটি একটি পুরানো থ্রেড। "কাঠামোটি একটি মোড়কের উপাদান লিখেছে এবং এটি শুরু হওয়ার পরে এক্সএমএল লেখককে অবস্থান দেয়" " এখানেই আমি লড়াই করছি। ফ্রেমওয়ার্কটি স্বয়ংক্রিয়ভাবে র‌্যাপারটি পরিচালনা করার এই পদক্ষেপটি এড়িয়ে যাওয়ার কোনও উপায় আছে? আমার একটি পরিস্থিতি আছে যেখানে আমাকে এই পদক্ষেপটি এড়ানো
জেমস

@ জেমস আমার জ্ঞানের সেরা হিসাবে নেই
মার্ক গ্রাভেল

34

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

বিপদগুলি হ'ল মার্ক এবং গ্রাভেল ইতিমধ্যে উল্লিখিত যা আছে তার পাশে লোকেল এবং খালি উপাদানগুলি পরিচালনা করছে।

http://www.codeproject.com/KB/XML/ImplementIXmlSerializable.aspx


দুর্দান্ত নিবন্ধ! আমি পরের বার যখন আমি কিছু ডেটা সিরিয়াল করতে দেখছি তখন অবশ্যই আমি এটি উল্লেখ করব।
গ্রেগ

ধন্যবাদ! ইতিবাচক প্রতিক্রিয়ার পরিমাণ এটি লেখায় যে পরিমাণ সময় ব্যয় করে তা পুরষ্কার দেয়। আপনি গভীরভাবে প্রশংসা করি যে আপনি এটি পছন্দ করেন! কিছু বিষয় সমালোচনা করতে জিজ্ঞাসা করতে দ্বিধা করবেন না।
jdehaan

উদাহরণগুলি এমএসডিএন উদ্ধৃত করার চেয়ে অনেক বেশি কার্যকর।

কোডেপ্রজেক্টের জন্য ধন্যবাদ, আমি যদি এটি করতে পারি তবে তাও ভোট দিয়েছি। এমএসডিএন এর তুলনায় বৈশিষ্ট্যগুলির স্টাফ সম্পূর্ণরূপে বিস্তৃত ছিল। উদাহরণস্বরূপ, আমার: আইএক্সএমএলসিরিয়েজযোগ্য ক্লাসটি যখন [সেরিয়ালাইজেবল (), এক্সএমএলটাইপ (নেমস্পেস = "মনিটরসেবা")] উত্পাদিত xsd.exe দ্বারা উপসর্গ করা হয়েছিল তখন ভেঙে যায়।
জন

8

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

আমাদের সমাধান আমাদের নিজস্ব সংজ্ঞায়িত করতে ছিল IXmlSerializableইন্টারফেস, সিস্টেম এক, যা একটি পদ্ধতি নামক যোগ থেকে উদ্ভূত WriteOuterXml()। আপনি অনুমান করতে পারেন, এই পদ্ধতিটি কেবল বাহ্যিক উপাদানটি লিখবে, তারপরে কল করবে WriteXml()এবং তারপরে উপাদানটির শেষে লিখবে। অবশ্যই, সিস্টেম এক্সএমএল সিরিয়ালাইজার এই পদ্ধতিটিকে কল করবে না, তাই এটি কেবল তখন কার্যকর যখন আমরা নিজস্ব সিরিয়ালাইজেশন করি, যাতে এটি আপনার ক্ষেত্রে সহায়ক হতে পারে বা নাও হতে পারে। একইভাবে, আমরা একটি ReadContentXml()পদ্ধতি যুক্ত করেছি, যা বাইরের উপাদানটি পড়ে না, কেবল এটির সামগ্রী।


5
সি # 3.0 এর সাহায্যে আপনি সম্ভবত এর পরিবর্তে কোনও এক্সটেনশন পদ্ধতি লিখে এটি করতে পারেন তবে একটি আকর্ষণীয় ধারণা।
মার্ক Gravell

2

আপনার কাছে যদি ইতিমধ্যে আপনার ক্লাসের একটি এক্সএমএল ডকুমেন্টের উপস্থাপনা থাকে বা এক্সএমএল কাঠামোগুলির সাথে কাজ করার জন্য এক্সএমএল ডকুমেন্টের উপায় পছন্দ করেন, তবে আইএক্সএমএলসিরাইজেবল বাস্তবায়নের একটি দ্রুত এবং নোংরা উপায় হল এই এক্সএমএলডোককে বিভিন্ন ফাংশনে সরিয়ে দেওয়া।

সতর্কতা: এক্সএমএল ডকুমেন্ট (এবং / অথবা এক্সডোকামেন্ট) এক্সএমএলআরডিটর / লেখকের চেয়ে ধীর গতির একটি ক্রম, সুতরাং যদি কর্মক্ষমতা একটি চূড়ান্ত প্রয়োজনীয়তা হয় তবে এই সমাধানটি আপনার পক্ষে নয়!

class ExampleBaseClass : IXmlSerializable { 
    public XmlDocument xmlDocument { get; set; }
    public XmlSchema GetSchema()
    {
        return null;
    }
    public void ReadXml(XmlReader reader)
    {
        xmlDocument.Load(reader);
    }

    public void WriteXml(XmlWriter writer)
    {
        xmlDocument.WriteTo(writer);
    }
}

0

ইন্টারফেস বাস্তবায়ন অন্যান্য উত্তরগুলি দ্বারা কভার করা হয়েছে, তবে আমি মূল উপাদানটির জন্য আমার 2-সেন্টে টস করতে চেয়েছিলাম।

আমি অতীতে শিখেছি রুট উপাদানটি মেটাডেটা হিসাবে স্থাপন করা পছন্দ করি। এর কয়েকটি সুবিধা রয়েছে:

  • যদি কোনও নাল বস্তু থাকে তবে এটি সিরিয়ালাইজ করতে পারে
  • একটি কোড পঠনযোগ্যতার দৃষ্টিকোণ থেকে, এটি উপলব্ধি করে

নীচে একটি সিরিয়ালযোগ্য অভিধানের উদাহরণ যেখানে অভিধানের মূল উপাদানটি সেইভাবে সংজ্ঞায়িত করা হয়েছে:

using System.Collections.Generic;

[System.Xml.Serialization.XmlRoot("dictionary")]
public partial class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, System.Xml.Serialization.IXmlSerializable
{
            public virtual System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public virtual void ReadXml(System.Xml.XmlReader reader)
    {
        var keySerializer = new System.Xml.Serialization.XmlSerializer(typeof(TKey));
        var valueSerializer = new System.Xml.Serialization.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();
            Add(key, value);
            reader.ReadEndElement();
            reader.MoveToContent();
        }

        reader.ReadEndElement();
    }

    public virtual void WriteXml(System.Xml.XmlWriter writer)
    {
        var keySerializer = new System.Xml.Serialization.XmlSerializer(typeof(TKey));
        var valueSerializer = new System.Xml.Serialization.XmlSerializer(typeof(TValue));
        foreach (TKey key in Keys)
        {
            writer.WriteStartElement("item");
            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();
            writer.WriteStartElement("value");
            var value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }
    }

    public SerializableDictionary() : base()
    {
    }

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

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