किसी ऑब्जेक्ट की गहरी प्रतिलिपि कैसे करें जिसे धारावाहिक (सी # में) के रूप में चिह्नित नहीं किया गया है?

मैं सी # में एक क्लिपबोर्ड ढेर बनाने का प्रयास कर रहा हूं। क्लिपबोर्ड डेटा System.Windows.Forms.DataObject ऑब्जेक्ट्स में संग्रहीत किया जाता है। मैं सीधे एक जेनेरिक सूची में प्रत्येक क्लिपबोर्ड एंट्री ( IDataObject ) को स्टोर करना चाहता था। बिटमैप्स (प्रतीत होता है) संग्रहीत करने के कारण मैं सोच रहा हूं कि सूची में जोड़ने से पहले मुझे पहले एक गहरी प्रतिलिपि करने की आवश्यकता है।

मैंने गहरी प्रतिलिपि बनाने के लिए बाइनरी सीरियलाइजेशन (नीचे देखें) का उपयोग करने का प्रयास किया लेकिन चूंकि System.Windows.Forms.DataObject serializable के रूप में चिह्नित नहीं है serialization चरण विफल रहता है। कोई विचार?

public IDataObject GetClipboardData()
{
    MemoryStream memoryStream = new MemoryStream();
    BinaryFormatter binaryFormatter = new BinaryFormatter();
    binaryFormatter.Serialize(memoryStream, Clipboard.GetDataObject());
    memoryStream.Position = 0;
    return (IDataObject) binaryFormatter.Deserialize(memoryStream);
}
3

3 उत्तर

मैंने नीचे दिए गए कोड को एक और प्रश्न के लिए लिखा है और शायद यह आपके लिए इस परिदृश्य में उपयोगी हो सकता है:

    public static class GhettoSerializer
    {
           //you could make this a factory method if your type
           //has a constructor that appeals to you (i.e. default 
           //parameterless constructor)
            public static void Initialize(T instance, IDictionary values)
            {
                    var props = typeof(T).GetProperties();

                   //my approach does nothing to handle rare properties with array indexers
                    var matches = props.Join(
                            values,
                            pi => pi.Name,
                            kvp => kvp.Key,
                            (property, kvp) =>
                                    new {
                                            Set = new Action(property.SetValue), 
                                            kvp.Value
                                    }
                    );

                    foreach (var match in matches)
                            match.Set(instance, match.Value, null);
            }
            public static IDictionary Serialize(T instance) { var props = typeof(T).GetProperties(); var ret = new Dictionary(); foreach (var property in props) { if (!property.CanWrite || !property.CanRead) continue; ret.Add(property.Name, property.GetValue(instance, null)); } return ret; } } 

हालांकि मुझे नहीं लगता कि यह आपकी समस्या का अंतिम समाधान होगा हालांकि यह आपको शुरू करने के लिए एक जगह दे सकता है।

3
जोड़ा
हाँ, यह कोड में एक बग है। typeof (T) के बजाय .GetProperties() , इसे instance.GetType ()। GetProperties() कहना चाहिए। असल में, मैं तर्क दूंगा कि इसे वास्तव में गुणों के बजाय फ़ील्ड का उपयोग करना चाहिए, लेकिन यह एक डिज़ाइन विकल्प है।
जोड़ा लेखक Timwi, स्रोत
इस पर एक शॉट लेने के लिए धन्यवाद (कक्षा नामकरण सम्मेलन के लिए अंक भी)। दुर्भाग्यवश IDataObject में कोई गुण नहीं है। डेटा विधियों का उपयोग करके "निकाला गया" है, इसलिए उपरोक्त कोड एक खाली शब्दकोश देता है।
जोड़ा लेखक cgray4, स्रोत

Copy of my answer to: difference between DataContract attribute and Serializable attribute in .net

मेरा जवाब वहां से कहीं बेहतर है, हालांकि ऊपर प्रश्न समाप्त होता है:

"... या शायद गहरे क्लोन बनाने का एक अलग तरीका?"

मैंने एक बार ऑब्जेक्ट स्ट्रक्चर के लिए प्रतिबिंब के माध्यम से कुछ निरीक्षण किया ताकि वे deserialization के लिए आवश्यक सभी असेंबली ढूंढ सकें और बूटस्ट्रैपिंग के लिए उन्हें क्रमबद्ध कर सकें।

कुछ काम के साथ कोई गहरी प्रतिलिपि बनाने के लिए एक समान विधि बना सकता है। असल में आपको एक पुनरावर्ती विधि की आवश्यकता होती है जो सर्कुलर संदर्भों का पता लगाने के लिए एक शब्दकोश के साथ ले जाती है। विधि के अंदर आप इस तरह के सभी क्षेत्रों का निरीक्षण करते हैं:

private void InspectRecursively(object input,
    Dictionary processedObjects)
{
  if ((input != null) && !processedObjects.ContainsKey(input))
  {
    processedObjects.Add(input, true);

    List fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); foreach (FieldInfo field in fields) { object nextInput = field.GetValue(input); if (nextInput is System.Collections.IEnumerable) { System.Collections.IEnumerator enumerator = (nextInput as System.Collections.IEnumerable).GetEnumerator(); while (enumerator.MoveNext()) { InspectRecursively(enumerator.Current, processedObjects); } } else { InspectRecursively(nextInput, processedObjects); } } } } 

To get it working you need to add an output object and something like System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type) to create the most shallowest copy (even without copying references) of each field's value. Finally you can set each field with something like field.SetValue(input, output)

हालांकि यह कार्यान्वयन पंजीकृत ईवेंट हैंडलर का समर्थन नहीं करता है, जो _ un _ deserializing द्वारा समर्थित है। इसके अतिरिक्त पदानुक्रम में प्रत्येक वस्तु तोड़ दी जाएगी, अगर उसके वर्ग के निर्माता को सभी क्षेत्रों को सेट करने के अलावा कुछ भी प्रारंभ करने की आवश्यकता है। आखिरी बिंदु केवल क्रमबद्धता के साथ काम करता है, यदि कक्षा में एक संबंधित कार्यान्वयन है, उदा। विधि [ऑनडिसेरियलाइज्ड] चिह्नित है, ISerializable लागू करता है ...।

0
जोड़ा

Serializable के लिए डॉक्स देखो और serialization सहायकों के बारे में सामान खोजें। आप बिटमैप को अपने स्वयं के क्रमबद्धता कोड में लपेट सकते हैं जो .NET ढांचे के साथ एकीकृत करता है।

0
जोड़ा