এক্সএমএল সিরিয়ালাইজেশন এবং উত্তরাধিকারী প্রকারগুলি


85

আমার আগের প্রশ্ন থেকে অনুসরণ করা আমি আমার বস্তুর মডেলটি এক্সএমএলকে সিরিয়ালায়িত করার জন্য কাজ করছি। তবে আমি এখন একটি সমস্যায় পড়েছি (কুইল আশ্চর্য!)।

আমার সমস্যাটি হ'ল আমার কাছে একটি সংগ্রহ রয়েছে, যা একটি বিমূর্ত বেস শ্রেণীর, যা কংক্রিট থেকে প্রাপ্ত প্রকারভেদ দ্বারা প্রসারিত।

আমি ভেবেছিলাম এটি জড়িত সমস্ত শ্রেণীর জন্য কেবল এক্সএমএল বৈশিষ্ট্য যুক্ত করা ভাল এবং সমস্ত কিছু পীচিযুক্ত হবে। দুঃখের বিষয়, ঘটনাটি না!

তাই আমি গুগলে কিছু খনন করেছি এবং আমি বুঝতে পারি এটি কেন কাজ করছে না। যে আসলে ধারাবাহিকভাবে করার জন্য কিছু চালাক প্রতিফলন করছেন বস্তু / XML থেকে, এবং তার পর থেকে বিমূর্ত ধরনের উপর ভিত্তি করে, এটা চিন্তা করতে পারবে না কী এটি কথা বলা । ভাল।XmlSerializer

আমি এই পৃষ্ঠাটি কোডপোজেজে এসেছি , যা দেখে মনে হচ্ছে এটি অনেক ভাল সাহায্য করতে পারে (এখনও পুরোপুরি পড়তে / গ্রাস করতে পারে) তবে আমি ভেবেছিলাম যে এই সমস্যাটি স্ট্যাকওভারফ্লো টেবিলেও আনতে চাই, আপনার কোনও ঝরঝরে আছে কিনা তা দেখতে এটিকে পেতে এবং দ্রুততম / হালকাতম পথে চলার জন্য হ্যাক / কৌশলগুলি।

আমার আরও একটি জিনিস যুক্ত করা উচিত তা হ'ল আমি এই পথে যেতে চাই নাXmlInclude । এটির সাথে কেবল খুব বেশি সংযোগ ঘটছে এবং সিস্টেমের এই ক্ষেত্রটি প্রচন্ড বিকাশাধীন, সুতরাং এটিই হবে সত্যিকারের রক্ষণাবেক্ষণের মাথাব্যথা!


4
আপনি ক্রমিক করার চেষ্টা করছেন এমন ক্লাসগুলি থেকে প্রাপ্ত কিছু প্রাসঙ্গিক কোড স্নিপেটগুলি দেখতে সহায়ক হবে।
রেক্স এম

সাথি: আমি আবার
খুললাম

বিট এই নিয়ে বিভ্রান্ত, যেহেতু এত দিন এই থ্রেডটিতে কিছুই নেই?
রব কুপার

আছে: উত্তর stackoverflow.com/questions/6737666/...
Odys

উত্তর:


54

সমস্যা সমাধান!

ঠিক আছে, তাই অবশেষে আমি সেখানে পৌঁছেছি (স্বীকারোক্তি দিয়ে এখান থেকে প্রচুর সহায়তায় !)।

সুতরাং সংক্ষেপে:

লক্ষ্যসমূহ:

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

চিহ্নিত করা বিষয়গুলি / পয়েন্টগুলি দ্রষ্টব্য:

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

সমাধান

আমি একটি জেনেরিক ক্লাস তৈরি করেছি, যাতে আপনি জেনেরিক প্রকারটিকে বিমূর্ত প্রকার হিসাবে নির্দিষ্ট করেন যা আপনি কাজ করবেন। এটি ক্লাসটিকে অ্যাবস্ট্রাক্ট টাইপ এবং কংক্রিট টাইপের মধ্যে "অনুবাদ" করার ক্ষমতা দেয় যেহেতু আমরা কাস্টিংকে হার্ড-কোড করতে পারি (যেমন আমরা এক্সএমএলসিরাইজারের ক্যান এর চেয়ে আরও তথ্য পেতে পারি)।

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

যেহেতু এক্সএমএলসিরাইজার কাস্ট করতে পারে না, তাই এটি করার জন্য আমাদের কোড সরবরাহ করতে হবে, সুতরাং অন্তর্নিহিত অপারেটরটি তখন ওভারলোড হয়ে যায় (আপনি এমনকি এটি করতে পারেন তা আমি কখনও জানতাম না!)।

অ্যাবস্ট্রাক্ট এক্সএমএলসায়ারাইজারের কোডটি হ'ল:

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

namespace Utility.Xml
{
    public class AbstractXmlSerializer<AbstractType> : IXmlSerializable
    {
        // Override the Implicit Conversions Since the XmlSerializer
        // Casts to/from the required types implicitly.
        public static implicit operator AbstractType(AbstractXmlSerializer<AbstractType> o)
        {
            return o.Data;
        }

        public static implicit operator AbstractXmlSerializer<AbstractType>(AbstractType o)
        {
            return o == null ? null : new AbstractXmlSerializer<AbstractType>(o);
        }

        private AbstractType _data;
        /// <summary>
        /// [Concrete] Data to be stored/is stored as XML.
        /// </summary>
        public AbstractType Data
        {
            get { return _data; }
            set { _data = value; }
        }

        /// <summary>
        /// **DO NOT USE** This is only added to enable XML Serialization.
        /// </summary>
        /// <remarks>DO NOT USE THIS CONSTRUCTOR</remarks>
        public AbstractXmlSerializer()
        {
            // Default Ctor (Required for Xml Serialization - DO NOT USE)
        }

        /// <summary>
        /// Initialises the Serializer to work with the given data.
        /// </summary>
        /// <param name="data">Concrete Object of the AbstractType Specified.</param>
        public AbstractXmlSerializer(AbstractType data)
        {
            _data = data;
        }

        #region IXmlSerializable Members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null; // this is fine as schema is unknown.
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            // Cast the Data back from the Abstract Type.
            string typeAttrib = reader.GetAttribute("type");

            // Ensure the Type was Specified
            if (typeAttrib == null)
                throw new ArgumentNullException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
                    "' because no 'type' attribute was specified in the XML.");

            Type type = Type.GetType(typeAttrib);

            // Check the Type is Found.
            if (type == null)
                throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
                    "' because the type specified in the XML was not found.");

            // Check the Type is a Subclass of the AbstractType.
            if (!type.IsSubclassOf(typeof(AbstractType)))
                throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
                    "' because the Type specified in the XML differs ('" + type.Name + "').");

            // Read the Data, Deserializing based on the (now known) concrete type.
            reader.ReadStartElement();
            this.Data = (AbstractType)new
                XmlSerializer(type).Deserialize(reader);
            reader.ReadEndElement();
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            // Write the Type Name to the XML Element as an Attrib and Serialize
            Type type = _data.GetType();

            // BugFix: Assembly must be FQN since Types can/are external to current.
            writer.WriteAttributeString("type", type.AssemblyQualifiedName);
            new XmlSerializer(type).Serialize(writer, _data);
        }

        #endregion
    }
}

সুতরাং, সেখান থেকে, আমরা কীভাবে এক্সএমএলসিরালাইজারকে ডিফল্টের চেয়ে আমাদের সিরিয়ালাইজারের সাথে কাজ করতে বলি? আমাদের অবশ্যই আমাদের প্রকারটি এক্সএমএল বৈশিষ্ট্য প্রকারের বৈশিষ্ট্যের মধ্যে পাস করতে হবে, উদাহরণস্বরূপ:

[XmlRoot("ClassWithAbstractCollection")]
public class ClassWithAbstractCollection
{
    private List<AbstractType> _list;
    [XmlArray("ListItems")]
    [XmlArrayItem("ListItem", Type = typeof(AbstractXmlSerializer<AbstractType>))]
    public List<AbstractType> List
    {
        get { return _list; }
        set { _list = value; }
    }

    private AbstractType _prop;
    [XmlElement("MyProperty", Type=typeof(AbstractXmlSerializer<AbstractType>))]
    public AbstractType MyProperty
    {
        get { return _prop; }
        set { _prop = value; }
    }

    public ClassWithAbstractCollection()
    {
        _list = new List<AbstractType>();
    }
}

এখানে আপনি দেখতে পাচ্ছেন, আমাদের কাছে একটি সংগ্রহ এবং একক সম্পত্তি প্রকাশিত হচ্ছে এবং আমাদের যা করতে হবে তা হল প্রকারটি যুক্ত করা সহজ Xml ঘোষণা করার নামে প্যারামিটার! : ডি

দ্রষ্টব্য: আপনি যদি এই কোডটি ব্যবহার করেন তবে আমি সত্যিই চিৎকারের প্রশংসা করব। এটি আরও বেশি লোককে সম্প্রদায়ের দিকে চালিত করতে সহায়তা করবে :)

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

আকর্ষণীয় সমস্যা এবং সমাধান করার জন্য ভাল মজা! :)


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

আমরা এক্সএমএল_ বৈশিষ্ট্যগুলি ব্যবহার করি যেখানে আমরা তালিকাটিকে অ্যারেগুলিতে রূপান্তর করি :)
আর্কটরাস

4
কারণ ক্লাসটিকে গতিময়ভাবে ইনস্ট্যান্ট করার জন্য একটি প্যারামিটারলেস কনস্ট্রাক্টর প্রয়োজন।
সিলাস হ্যানসেন

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

4
চমৎকার কোড। নোট করুন যে প্যারামিটারলেস কনট্রাক্টর ঘোষিত হতে পারে privateবা protectedএটি প্রয়োগ করা যেতে পারে যে এটি অন্য শ্রেণিতে উপলব্ধ নয়।
tcovo

9

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

এক্সট্রা টাইপস প্যারাম সহ এক্সএমএলসিরিয়ালাইজার কনস্ট্রাক্টর

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


এটি আমি যা করার চেষ্টা করে যাচ্ছি, তবে আমি ভাবছিলাম এমনটা সহজ নয়: স্ট্যাকওভারফ্লো.com
লুকা

এটি একটি খুব পুরানো পোস্ট তবে যে কেউ আমাদের মতো করে এটি বাস্তবায়নের দিকে তাকাচ্ছেন, দয়া করে নোট করুন এক্সট্রোলটাইপস পরম সহ এক্সএমএসআরশায়ালাইজারের কনস্ট্রাক্টর উড়ে যাওয়ার সময় যে সমাবেশগুলি উত্পন্ন করে তা ক্যাশে করে না । এটি আমাদের মেমরি ফুটো ডিবাগ করার কয়েক সপ্তাহ ব্যয় করে। সুতরাং আপনি যদি স্বীকৃত উত্তরের কোড সহ অতিরিক্ত প্রকারগুলি ব্যবহার করতে চান তবে সিরিয়ালাইজারটিকে ক্যাশে করুন । এই আচরণটি এখানে নথিভুক্ত করা হয়েছে: support.microsoft.com/en-us/kb/886385
জুলিয়েন লেবোট

3

গুরুতরভাবে, পোকসগুলির একটি এক্সটেনসিবল কাঠামো কখনই এক্সএমএলকে নির্ভরযোগ্যভাবে সিরিয়ালাইজ করতে পারে না। আমি এটি বলছি কারণ আমি গ্যারান্টি দিতে পারি যে কেউ আসবেন, আপনার ক্লাসটি প্রসারিত করবেন এবং এটি বক করবেন।

আপনার অবজেক্ট গ্রাফগুলি সিরিয়াল করার জন্য আপনার XAML ব্যবহার করা উচিত। এটি এটি করার জন্য ডিজাইন করা হয়েছে, যেখানে এক্সএমএল সিরিয়ালাইজেশন নেই।

এক্সএএমএল সিরিয়ালাইজার এবং ডিসরিয়ালাইজার কোনও সমস্যা ছাড়াই জেনারিকগুলি পরিচালনা করে, বেস ক্লাস এবং ইন্টারফেসের সংগ্রহ (যতক্ষণ না সংগ্রহগুলি তারা প্রয়োগ করে IListবা প্রয়োগ করে IDictionary)। কিছু সাবধানবাণী রয়েছে যেমন আপনার কেবলমাত্র পঠন সংগ্রহের বৈশিষ্ট্যগুলি দিয়ে চিহ্নিত করে DesignerSerializationAttribute, তবে এই কোণার কেসগুলি পরিচালনা করতে আপনার কোডটি পুনরায় কাজ করা খুব কঠিন নয়।


লিঙ্কটি মারা গেছে বলে মনে হচ্ছে
বেকারিবস

আচ্ছা ভালো. আমি কিছুটা কড়া নেব। বিষয়টি সম্পর্কে প্রচুর অন্যান্য সংস্থান রয়েছে।

2

এই সম্পর্কে একটি দ্রুত আপডেট, আমি ভুলিনি!

আরও কিছু গবেষণা করছেন, দেখে মনে হচ্ছে আমি একজন বিজয়ীর সাথে রয়েছি, কেবল কোড বাছাই করা দরকার।

এখনও পর্যন্ত, আমি নিম্নলিখিত:

  • XmlSeralizer মূলত একটি বর্গ যে শ্রেণীর এটা serializing হয় তার উপর কিছু ছিমছাম প্রতিফলন নেই। এটি প্রকারের ভিত্তিতে সিরিয়ালযুক্ত বৈশিষ্ট্যগুলি নির্ধারণ করে ।
  • সমস্যাটি হওয়ার কারণটি হ'ল কারণ কোনও ধরণের অমিল ঘটছে, এটি বেসটাইপ প্রত্যাশা করছে তবে বাস্তবে ডেরিভেডটাইপ প্রাপ্তি করে ... আপনি যখন ভাবতে পারেন যে এটি বহুত্বপূর্ণভাবে এটি চিকিত্সা করবে তবে এটি পুরোপুরি অতিরিক্ত লোড জড়িত করার পরে তা নয় doesn't প্রতিবিম্ব এবং টাইপ-চেকিং, যা এটি করার জন্য ডিজাইন করা হয়নি।

এই আচরণটি সিরিয়ালাইজারের মধ্যস্থতা হিসাবে কাজ করতে একটি প্রক্সি ক্লাস তৈরি করে ওভাররাইড (কোড মুলতুবি) হতে সক্ষম হবে বলে মনে হয়। এটি মূলত উদ্ভূত শ্রেণীর ধরণ নির্ধারণ করবে এবং তারপরে এটিকে স্বাভাবিক হিসাবে সিরিয়ালাইজ করবে। এই প্রক্সি ক্লাসটি তখন সেই এক্সএমএলকে মূল সিরিয়ালাইজে ফিরে যাবে ..

এই জায়গা দেখুন! ^ _ ^


2

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

type.AssemblyQualifiedName

যা দেখে মনে হচ্ছে

TopNamespace.SubNameSpace.ContainingClass+NestedClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089

এটিতে আপনার সমাবেশ বৈশিষ্ট্য এবং সংস্করণ রয়েছে ...

এখন আপনি যদি নিজের সমাবেশ সংস্করণটি পরিবর্তন করার চেষ্টা করেন বা আপনি এটি সাইন করার সিদ্ধান্ত নিয়ে থাকেন তবে এই deserialization কাজ করে না ...


1

আমি এর মতো কাজ করেছি। আমি সাধারণত যা করি তা নিশ্চিত করা হয় যে সমস্ত এক্সএমএল সিরিয়ালাইজেশন বৈশিষ্ট্যগুলি কংক্রিট ক্লাসে রয়েছে এবং কেবলমাত্র সেই শ্রেণীর কলগুলিতে বৈশিষ্ট্যগুলি বেস ক্লাসগুলিতে (যেখানে প্রয়োজন হয়) তথ্য পুনরুদ্ধার করতে হবে যা সিরিয়ালাইজার কল করলে ডি / সিরিয়ালযুক্ত হবে information যারা সম্পত্তি। এটি কিছুটা কোডিংয়ের কাজ, তবে সিরিয়ালাইজারকে কেবল সঠিক কাজ করতে বাধ্য করার চেষ্টা করার চেয়ে এটি আরও ভাল কাজ করে।


1

আরও ভাল, স্বরলিপি ব্যবহার করে:

[XmlRoot]
public class MyClass {
    public abstract class MyAbstract {} 
    public class MyInherited : MyAbstract {} 
    [XmlArray(), XmlArrayItem(typeof(MyInherited))] 
    public MyAbstract[] Items {get; set; } 
}

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