গভীর ক্লোনিং অবজেক্টস


2225

আমি এরকম কিছু করতে চাই:

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();

এবং তারপরে নতুন অবজেক্টে পরিবর্তনগুলি করুন যা মূল বস্তুর প্রতিফলিত হয় না।

আমার প্রায়শই এই কার্যকারিতাটির প্রয়োজন হয় না, সুতরাং যখন এটি প্রয়োজনীয় হয় তখন আমি একটি নতুন অবজেক্ট তৈরি করা এবং তারপরে প্রতিটি সম্পত্তি পৃথকভাবে অনুলিপি করার চেষ্টা করেছি, তবে হ্যান্ডলিংয়ের আরও ভাল বা আরও মার্জিত উপায় আছে এমন অনুভূতিটি আমাকে সর্বদা ছেড়ে দেয় it পরিস্থিতি.

আমি কীভাবে কোনও বস্তুর ক্লোন বা গভীর অনুলিপি করতে পারি যাতে ক্লোনযুক্ত অবজেক্টটি কোনও মূল পরিবর্তন করেও কোনও পরিবর্তন না করে সংশোধন করা যায়?


81
দরকারী হতে পারে: "কেন কোনও জিনিস অনুলিপি করা একটি ভয়ঙ্কর কাজ?" agiledeveloper.com/articles/cloning072002.htm
পেড্রো 77


18
আপনার অটোম্যাপারটি দেখে নেওয়া উচিত
ড্যানিয়েল লিটল

3
আপনার সমাধানটি আরও জটিল, আমি এটি পড়ে হারিয়ে ফেললাম ... হেইহে। আমি একটি ডিপক্লোন ইন্টারফেস ব্যবহার করছি। সর্বজনীন ইন্টারফেস আইডিপীপ ক্লোনএবল <T> Deep টি ডিপক্লোন (); }
পেড্রো 77

1
@ পেড্রো 7777 - যদিও আকর্ষণীয়ভাবে, নিবন্ধটি cloneক্লাসে একটি পদ্ধতি তৈরি করার কথা বলে শেষ হয়েছে , তারপরে এটি কোনও অভ্যন্তরীণ, প্রাইভেট কনস্ট্রাক্টরকে কল করুন যা উত্তীর্ণ হবে this। সুতরাং অনুলিপি করা ভয়ঙ্কর [sic], তবে সাবধানতার সাথে অনুলিপি করা (এবং নিবন্ধটি অবশ্যই পড়ার পক্ষে মূল্যবান নয়)। ; ^)
রাফিন

উত্তর:


1715

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

অন্য কোথাও উল্লিখিত হিসাবে এটির জন্য আপনার বস্তুগুলি সিরিয়ালযোগ্য হতে পারে।

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
    /// <summary>
    /// Perform a deep Copy of the object.
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", nameof(source));
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }
}

ধারণাটি হ'ল এটি আপনার অবজেক্টটিকে সিরিয়ালাইজ করে এবং তারপরে এটি একটি তাজা বস্তুতে ডিসরিয়ালাইজ করে। সুবিধাটি হ'ল যখন কোনও বস্তু খুব জটিল হয়ে যায় তখন আপনাকে নিজের সমস্ত কিছুর ক্লোনিং সম্পর্কে চিন্তা করতে হবে না।

এবং এক্সটেনশন পদ্ধতিগুলি ব্যবহার করে (মূলত উত্সযুক্ত উত্স থেকেও):

আপনি যদি সি # 3.0 এর নতুন এক্সটেনশন পদ্ধতিগুলি ব্যবহার করতে পছন্দ করেন তবে নীচের স্বাক্ষর রাখতে পদ্ধতিটি পরিবর্তন করুন:

public static T Clone<T>(this T source)
{
   //...
}

এখন পদ্ধতি কল সহজ হয়ে যায় objectBeingCloned.Clone();

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

/// <summary>
/// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{            
    // Don't serialize a null object, simply return the default for that object
    if (Object.ReferenceEquals(source, null))
    {
        return default(T);
    }

    // initialize inner objects individually
    // for example in default constructor some list property initialized with some values,
    // but in 'source' these items are cleaned -
    // without ObjectCreationHandling.Replace default constructor values will be added to result
    var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

24
stackoverflow.com/questions/78536/cloning-objects-in-c/… এর উপরের কোডটির একটি লিঙ্ক রয়েছে [এবং এইরকম আরও দুটি বাস্তবায়নের উল্লেখ রয়েছে, যার একটি আমার প্রসঙ্গে আরও উপযুক্ত]]
রুবেন বারটেলিংক

102
সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশনে উল্লেখযোগ্য ওভারহেড জড়িত যা প্রয়োজনীয় নয়। আই সিলনেবল ইন্টারফেস এবং সি # তে মেম্বারওয়াইজ () ক্লোন পদ্ধতি দেখুন।
ডিভে

18
@ ডেভিড, মঞ্জুর করা হয়েছে, তবে যদি জিনিসগুলি হালকা হয় এবং এটি ব্যবহার করার সময় পারফরম্যান্স হিট হয় আপনার প্রয়োজনীয়তার জন্য খুব বেশি না হয়, তবে এটি একটি দরকারী টিপ। আমি লুপে প্রচুর পরিমাণে ডেটা সহ এটিকে নিবিড়ভাবে ব্যবহার করি নি, আমি স্বীকার করি, তবে আমি কোনও একক পারফরম্যান্স উদ্বেগ দেখিনি।
জনক

16
@ আমির: আসলে, না: typeof(T).IsSerializableটাইপটি যদি [Serializable]বৈশিষ্ট্যের সাথে চিহ্নিত করা হয় তবে এটিও সত্য । এটি ISerializableইন্টারফেস বাস্তবায়ন করতে হবে না ।
ড্যানিয়েল গেহরিগার

11
কেবল ভেবেছি আমি উল্লেখ করতে পারি যে এই পদ্ধতিটি দরকারী, এবং আমি নিজে এটি অনেক সময় ব্যবহার করেছি, এটি মাঝারি ট্রাস্টের সাথে মোটেই উপযুক্ত নয় - সুতরাং আপনার যদি সামঞ্জস্যতার প্রয়োজন হয় এমন কোড লিখছেন কিনা তা দেখুন। বাইনারি ফরম্যাটর ব্যক্তিগত ক্ষেত্র অ্যাক্সেস এবং এইভাবে আংশিক আস্থা পরিবেশের জন্য ডিফল্ট অনুমতি সেট কাজ করতে পারে না। আপনি অন্য সিরিয়ালাইজার চেষ্টা করতে পারেন, তবে নিশ্চিত হয়ে নিন যে আপনার কলার জানেন যে আগত বিষয়টি ব্যক্তিগত ক্ষেত্রে নির্ভর করে তবে ক্লোনটি নিখুঁত হতে পারে না।
অ্যালেক্স নরক্লিফ

298

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

public static T Clone<T>(T source)
{
    var serialized = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(serialized);
}

এছাড়াও, আপনি এই এক্সটেনশন পদ্ধতিটি ব্যবহার করতে পারেন

public static class SystemExtension
{
    public static T Clone<T>(this T source)
    {
        var serialized = JsonConvert.SerializeObject(source);
        return JsonConvert.DeserializeObject<T>(serialized);
    }
}

13
সলিউটিজন বাইনারি ফরম্যাটার সমাধানের চেয়ে আরও দ্রুততর,। নেট সিরিয়ালাইজেশন পারফরম্যান্স তুলনা
Esckar

3
এর জন্য ধন্যবাদ. আমি সিএস # এর জন্য মঙ্গোডিবি ড্রাইভারের সাথে যে বিএসএন সিরিয়ালাইজারটি পাঠিয়েছিল সেগুলির সাথে মূলত একই জিনিসটি করতে পেরেছিলাম।
ইওর

3
এটি আমার পক্ষে সেরা উপায়, তবে আমি ব্যবহার করি Newtonsoft.Json.JsonConvertতবে এটি একই
পিয়েরে

1
এটির কাজ করার জন্য ক্লোন থেকে অবজেক্টটি ইতিমধ্যে উল্লিখিত হিসাবে সিরিয়ালযোগ্য হওয়া দরকার - এর অর্থ এটি উদাহরণস্বরূপ যে এটিতে বিজ্ঞপ্তি নির্ভরতা নাও থাকতে পারে
রেডোমেট

2
আমি মনে করি এটিই সেরা সমাধান কারণ বেশিরভাগ প্রোগ্রামিং ভাষার ক্ষেত্রে প্রয়োগটি প্রয়োগ করা যেতে পারে।
মিঃ 5

176

কারণ ব্যবহার না করার ICloneable হয় না কারণ এটি একটি জেনেরিক ইন্টারফেস নেই। এটি ব্যবহার না করার কারণ এটি অস্পষ্ট । আপনি কোনও অগভীর বা গভীর অনুলিপি পাচ্ছেন কিনা তা স্পষ্ট করে দেয় না; এটি প্রয়োগকারী উপর।

হ্যাঁ, MemberwiseCloneএকটি অগভীর অনুলিপি তৈরি করে, তবে এর বিপরীতে MemberwiseCloneনয় Clone; এটি হতে পারে, সম্ভবত DeepClone, যার অস্তিত্ব নেই। আপনি যখন কোনও বস্তুটির আইসিএলনেবল ইন্টারফেসের মাধ্যমে ব্যবহার করেন, আপনি বুঝতে পারবেন না যে অন্তর্নিহিত অবজেক্টটি কোন ধরণের ক্লোনিং করে forms (এবং এক্সএমএল মন্তব্যগুলি এটি পরিষ্কার করে দেবে না, কারণ আপনি বস্তুর ক্লোন পদ্ধতির চেয়ে ইন্টারফেসের মতামত পাবেন))

আমি সাধারণত যা করি তা হ'ল একটি Copyপদ্ধতি তৈরি করা যা আমি যা চাই ঠিক তা করে।


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

29
আপনার উদাহরণ সমস্যার চিত্রিত করে। ধরুন আপনার কাছে একটি অভিধান রয়েছে <স্ট্রিং, গ্রাহক>। ক্লোন করা অভিধানে কি গ্রাহক অবজেক্টের মূল বা একই কপিরাইটের অনুলিপি থাকা উচিত? যে কোনও একটির জন্য যুক্তিসঙ্গত ব্যবহারের কেস রয়েছে। তবে আইক্লোনেবল আপনি কোনটি পাবেন তা পরিষ্কার করে দেয় না। এ কারণেই এটি কার্যকর নয়।
রায়ান লুন্ডি

@ কাইরলেসা মাইক্রোসফ্ট এমএসডিএন নিবন্ধটি আসলে আপনি একটি গভীর বা অগভীর অনুলিপিটির জন্য অনুরোধ করছেন কিনা তা না জানার এই সমস্যাটি উল্লেখ করেছে।
ক্রাশ

ডুপ্লিকেট থেকে উত্তর stackoverflow.com/questions/129389/... বর্ণনা অনুলিপি এক্সটেনশন, রিকার্সিভ MembershipClone উপর ভিত্তি করে
মাইকেল Freidgeim

123

এখানে লিঙ্কযুক্ত অনেকগুলি বিকল্প সম্পর্কে অনেকগুলি পড়ার পরে এবং এই সমস্যার সম্ভাব্য সমাধানের পরে, আমি বিশ্বাস করি যে সমস্ত অপশনগুলি ইয়ান পি এর লিঙ্কে খুব ভালভাবে সংক্ষিপ্ত করা হয়েছে (সমস্ত বিকল্পগুলি সেগুলির বিভিন্নতা) এবং সর্বোত্তম সমাধানটি সরবরাহ করে by প্রশ্ন মন্তব্য উপর পেড্রো 77 এর লিঙ্ক

সুতরাং আমি কেবল এখানে 2 টি রেফারেন্সের প্রাসঙ্গিক অংশগুলি অনুলিপি করব। এইভাবে আমাদের থাকতে পারে:

সি শার্পে ক্লোনিং অবজেক্টের জন্য সবচেয়ে ভাল কাজ!

প্রথম এবং সর্বাগ্রে, সেগুলি আমাদের সমস্ত বিকল্প:

নিবন্ধ প্রকাশের গাছ দ্বারা ফাস্ট ডীপ কপি এছাড়াও ধারাবাহিকতাতে, প্রতিফলন এবং এক্সপ্রেশন গাছ দ্বারা ক্লোনিং কর্মক্ষমতা তুলনা হয়েছে।

আমি কেন আইসিএলনেবল (যেমন ম্যানুয়ালি) বেছে নিই

মিঃ ভেঙ্কট সুব্রামণিয়াম (এখানে অপ্রয়োজনীয় লিঙ্ক) কেন তা বিশদভাবে ব্যাখ্যা করেছেন

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

এটি তাঁর সমাপ্তির আমার সামান্য পরিবর্তিত সংস্করণ:

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

আশা করি এই বাস্তবায়ন বিষয়গুলি পরিষ্কার করে দিতে পারে:

public class Person : ICloneable
{
    private final Brain brain; // brain is final since I do not want 
                // any transplant on it once created!
    private int age;
    public Person(Brain aBrain, int theAge)
    {
        brain = aBrain; 
        age = theAge;
    }
    protected Person(Person another)
    {
        Brain refBrain = null;
        try
        {
            refBrain = (Brain) another.brain.clone();
            // You can set the brain in the constructor
        }
        catch(CloneNotSupportedException e) {}
        brain = refBrain;
        age = another.age;
    }
    public String toString()
    {
        return "This is person with " + brain;
        // Not meant to sound rude as it reads!
    }
    public Object clone()
    {
        return new Person(this);
    }
    
}

এখন ব্যক্তি থেকে ক্লাস প্রাপ্তি বিবেচনা করুন।

public class SkilledPerson extends Person
{
    private String theSkills;
    public SkilledPerson(Brain aBrain, int theAge, String skills)
    {
        super(aBrain, theAge);
        theSkills = skills;
    }
    protected SkilledPerson(SkilledPerson another)
    {
        super(another);
        theSkills = another.theSkills;
    }

    public Object clone()
    {
        return new SkilledPerson(this);
    }
    public String toString()
    {
        return "SkilledPerson: " + super.toString();
    }
}

আপনি নিম্নলিখিত কোডটি চালানোর চেষ্টা করতে পারেন:

public class User
{
    public static void play(Person p)
    {
        Person another = (Person) p.clone();
        System.out.println(p);
        System.out.println(another);
    }
    public static void main(String[] args)
    {
        Person sam = new Person(new Brain(), 1);
        play(sam);
        SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer");
        play(bob);
    }
}

উত্পাদিত আউটপুট হবে:

This is person with Brain@1fcc69
This is person with Brain@253498
SkilledPerson: This is person with SmarterBrain@1fef6f
SkilledPerson: This is person with SmarterBrain@209f4e

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


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

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

আপনি সিজিবিআর ক্লোন জেনারেটরটি ব্যবহার করতে পারেন এবং কোডটি ম্যানুয়ালি না লিখে অনুরূপ ফলাফল পেতে পারেন।
টক্স্যান্ট্রন

মধ্যবর্তী ভাষার প্রয়োগ কার্যকর
মাইকেল ফ্রিজিম

সি # তে কোন চূড়ান্ত নেই
কনরাড

83

আমি একটি ক্লোন থেকে একটি অনুলিপি নির্মাণকারী পছন্দ। উদ্দেশ্য পরিষ্কার হয়।


5
.নেটের অনুলিপি নির্মাণকারী নেই।
পপ ক্যাটালিন

48
নিশ্চিত এটি এটি করেছে: নতুন মাইবজেক্ট (অবজেক্টো ক্লোনফ্রম) কেবলমাত্র এমন একটি সিটার ঘোষণা করুন যা বস্তুকে প্যারামিটার হিসাবে ক্লোন করতে নিয়ে যায়।
নিক

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

14
অনুলিপি ctor জন্য +1। আপনাকে প্রতিটি ধরণের অবজেক্টের জন্য ম্যানুয়ালি একটি ক্লোন () ফাংশন লিখতে হবে এবং যখন আপনার শ্রেণি শ্রেণিবিন্যাস কয়েক স্তর গভীর হয় তখন তার জন্য সৌভাগ্য।
অ্যান্ড্রু গ্রান্ট

3
অনুলিপি নির্মাণকারীদের সাথে আপনি যদিও শ্রেণিবদ্ধতা হারাবেন। agiledeveloper.com/articles/cloning072002.htm
উইল

41

সমস্ত জনসাধারণের সম্পত্তি অনুলিপি করার সহজ বর্ধিত পদ্ধতি। কোন অবজেক্টের জন্য কাজ করে এবং না হতে বর্গ প্রয়োজন [Serializable]। অন্যান্য অ্যাক্সেস স্তরের জন্য বাড়ানো যেতে পারে।

public static void CopyTo( this object S, object T )
{
    foreach( var pS in S.GetType().GetProperties() )
    {
        foreach( var pT in T.GetType().GetProperties() )
        {
            if( pT.Name != pS.Name ) continue;
            ( pT.GetSetMethod() ).Invoke( T, new object[] 
            { pS.GetGetMethod().Invoke( S, null ) } );
        }
    };
}

15
দুর্ভাগ্যক্রমে, এটি ত্রুটিযুক্ত। এটি অবজেক্ট ওনে কল করার সমান ty এটি বৈশিষ্ট্যের মানগুলি ক্লোন করবে না।
অ্যালেক্স নরক্লিফ

1
অ্যালেক্স নরক্লিফের কাছে: প্রশ্নের লেখক "প্রতিটি সম্পত্তি অনুলিপি" করার চেয়ে ক্লোনিংয়ের বিষয়ে জিজ্ঞাসা করেছিলেন। বেশিরভাগ ক্ষেত্রে সম্পত্তিগুলির যথাযথ সদৃশ প্রয়োজন হয় না।
কনস্ট্যান্টিন সালাভাতভ

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

33

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

এটি কিভাবে ব্যবহার করতে?

ক্ষেত্র এবং বৈশিষ্ট্যগুলির মধ্যে নির্ধারিত স্বরের সাথে নিজের Cloneবা Copyপদ্ধতিগুলি লেখার পরিবর্তে এক্সপ্রেশন ট্রি ব্যবহার করে প্রোগ্রামটি নিজের জন্য করে তোলে। GetClone<T>()এক্সটেনশন পদ্ধতি হিসাবে চিহ্নিত পদ্ধতিটি আপনাকে কেবল আপনার উদাহরণে এটি কল করতে দেয়:

var newInstance = source.GetClone();

আপনি চয়ন করতে পারেন কি থেকে অনুলিপি করা উচিত sourceকরতে newInstanceব্যবহার CloningFlagsenum:

var newInstance 
    = source.GetClone(CloningFlags.Properties | CloningFlags.CollectionItems);

কি ক্লোন করা যেতে পারে?

  • আদিম (ইন্ট, ইউিন্ট, বাইট, ডাবল, চর ইত্যাদি), জানা অপরিবর্তনীয় প্রকারগুলি (ডেটটাইম, টাইমস্প্যান, স্ট্রিং) এবং প্রতিনিধিরা (অ্যাকশন, ফানক ইত্যাদি)
  • Nullable
  • টি [] অ্যারে
  • জেনেরিক ক্লাস এবং স্ট্রাক্ট সহ কাস্টম ক্লাস এবং স্ট্রাক্ট।

নিম্নলিখিত শ্রেণি / কাঠামোর সদস্যরা অভ্যন্তরীণভাবে ক্লোন করা হয়েছে:

  • জনসাধারণের মান, কেবল পাঠযোগ্য ক্ষেত্র নয়
  • উভয়ই পাবলিক বৈশিষ্ট্যগুলির মানগুলি অ্যাক্সেসর পান এবং সেট করুন
  • আইকোলিকেশন প্রয়োগকারী ধরণের জন্য আইটেম সংগ্রহ করুন

এটা কত দ্রুত?

সমাধানটি তারপরে দ্রুত প্রতিবিম্বিত হয়, কারণ সদস্যদের তথ্য কেবল একবারে সংগ্রহ করা উচিত, এর আগে GetClone<T>প্রদত্ত ধরণের জন্য প্রথমবারের জন্য ব্যবহৃত হয় T

এটি সিরিয়ালাইজেশন ভিত্তিক সমাধানের চেয়ে দ্রুততর যখন আপনি একই ধরণের একাধিক উদাহরণগুলি ক্লোন করেন T

এবং আরও ...

ডকুমেন্টেশনে উত্পন্ন প্রকাশ সম্পর্কে আরও পড়ুন ।

এর জন্য নমুনা এক্সপ্রেশন ডিবাগ তালিকা List<int>:

.Lambda #Lambda1<System.Func`4[System.Collections.Generic.List`1[System.Int32],CloneExtensions.CloningFlags,System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]],System.Collections.Generic.List`1[System.Int32]]>(
    System.Collections.Generic.List`1[System.Int32] $source,
    CloneExtensions.CloningFlags $flags,
    System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]] $initializers) {
    .Block(System.Collections.Generic.List`1[System.Int32] $target) {
        .If ($source == null) {
            .Return #Label1 { null }
        } .Else {
            .Default(System.Void)
        };
        .If (
            .Call $initializers.ContainsKey(.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32]))
        ) {
            $target = (System.Collections.Generic.List`1[System.Int32]).Call ($initializers.Item[.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32])]
            ).Invoke((System.Object)$source)
        } .Else {
            $target = .New System.Collections.Generic.List`1[System.Int32]()
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)
        ) {
            .Default(System.Void)
        } .Else {
            .Default(System.Void)
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)
        ) {
            .Block() {
                $target.Capacity = .Call CloneExtensions.CloneFactory.GetClone(
                    $source.Capacity,
                    $flags,
                    $initializers)
            }
        } .Else {
            .Default(System.Void)
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)
        ) {
            .Block(
                System.Collections.Generic.IEnumerator`1[System.Int32] $var1,
                System.Collections.Generic.ICollection`1[System.Int32] $var2) {
                $var1 = (System.Collections.Generic.IEnumerator`1[System.Int32]).Call $source.GetEnumerator();
                $var2 = (System.Collections.Generic.ICollection`1[System.Int32])$target;
                .Loop  {
                    .If (.Call $var1.MoveNext() != False) {
                        .Call $var2.Add(.Call CloneExtensions.CloneFactory.GetClone(
                                $var1.Current,
                                $flags,


                         $initializers))
                } .Else {
                    .Break #Label2 { }
                }
            }
            .LabelTarget #Label2:
        }
    } .Else {
        .Default(System.Void)
    };
    .Label
        $target
    .LabelTarget #Label1:
}

}

সি # কোডের মতো একই অর্থ কী:

(source, flags, initializers) =>
{
    if(source == null)
        return null;

    if(initializers.ContainsKey(typeof(List<int>))
        target = (List<int>)initializers[typeof(List<int>)].Invoke((object)source);
    else
        target = new List<int>();

    if((flags & CloningFlags.Properties) == CloningFlags.Properties)
    {
        target.Capacity = target.Capacity.GetClone(flags, initializers);
    }

    if((flags & CloningFlags.CollectionItems) == CloningFlags.CollectionItems)
    {
        var targetCollection = (ICollection<int>)target;
        foreach(var item in (ICollection<int>)source)
        {
            targetCollection.Add(item.Clone(flags, initializers));
        }
    }

    return target;
}

আপনি কীভাবে নিজের Cloneপদ্ধতি লিখতে চান তা কি ঠিক নয় List<int>?


2
নুগেটে এটি হওয়ার সম্ভাবনা কী কী? এটি সেরা সমাধান মত মনে হচ্ছে। কীভাবে এটি এনক্লোনের সাথে তুলনা করে ?
ক্রাশ করুন

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

মোটেও নয়, আপনি প্রতিবিম্ব সম্পর্কে ভুল করেছেন, আপনার এটি ঠিকভাবে ক্যাশে করা উচিত। নীচের আমার উত্তর চেক stackoverflow.com/a/34368738/4711853
রোমা Borodov

31

আচ্ছা সিলভারলাইটে আইক্লোনেবল ব্যবহার করতে আমার সমস্যা হয়েছে, তবে আমি চূড়ান্তকরণের ধারণাটি পছন্দ করেছি, এক্সএমএলকে আমি সিরাালাইজ করতে পারি, তাই আমি এটি করেছি:

static public class SerializeHelper
{
    //Michael White, Holly Springs Consulting, 2009
    //michael@hollyspringsconsulting.com
    public static T DeserializeXML<T>(string xmlData) where T:new()
    {
        if (string.IsNullOrEmpty(xmlData))
            return default(T);

        TextReader tr = new StringReader(xmlData);
        T DocItms = new T();
        XmlSerializer xms = new XmlSerializer(DocItms.GetType());
        DocItms = (T)xms.Deserialize(tr);

        return DocItms == null ? default(T) : DocItms;
    }

    public static string SeralizeObjectToXML<T>(T xmlObject)
    {
        StringBuilder sbTR = new StringBuilder();
        XmlSerializer xmsTR = new XmlSerializer(xmlObject.GetType());
        XmlWriterSettings xwsTR = new XmlWriterSettings();

        XmlWriter xmwTR = XmlWriter.Create(sbTR, xwsTR);
        xmsTR.Serialize(xmwTR,xmlObject);

        return sbTR.ToString();
    }

    public static T CloneObject<T>(T objClone) where T:new()
    {
        string GetString = SerializeHelper.SeralizeObjectToXML<T>(objClone);
        return SerializeHelper.DeserializeXML<T>(GetString);
    }
}

31

আপনি যদি ইতিমধ্যে ভ্যালুআইঞ্জেক্টর বা অটোম্যাপারের মতো একটি তৃতীয় পক্ষের অ্যাপ্লিকেশন ব্যবহার করে থাকেন তবে আপনি এটির মতো কিছু করতে পারেন:

MyObject oldObj; // The existing object to clone

MyObject newObj = new MyObject();
newObj.InjectFrom(oldObj); // Using ValueInjecter syntax

এই পদ্ধতিটি ব্যবহার করে আপনাকে প্রয়োগ করতে হবে না ISerializableবা ICloneableআপনার অবজেক্টগুলিতে নেই। এটি এমভিসি / এমভিভিএম প্যাটার্নের সাথে সাধারণ, তাই এর মতো সহজ সরঞ্জাম তৈরি করা হয়েছে।

দেখতে GitHub থেকে ValueInjecter গভীর ক্লোনিং নমুনা


25

এর মতো এক্সটেনশন পদ্ধতি কার্যকর করা সবচেয়ে ভাল

public static T DeepClone<T>(this T originalObject)
{ /* the cloning code */ }

এবং তারপরে সমাধানের যে কোনও জায়গায় এটি ব্যবহার করুন

var copy = anyObject.DeepClone();

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

  1. সিরিয়ালাইজেশন দ্বারা (সংক্ষিপ্ততম কোড)
  2. প্রতিবিম্ব দ্বারা - 5x দ্রুত
  3. এক্সপ্রেশন ট্রি দ্বারা - 20x দ্রুত

সমস্ত লিঙ্কযুক্ত পদ্ধতি ভাল কাজ করছে এবং গভীরভাবে পরীক্ষা করা হয়েছিল।


আপনি কোডেপ্রজেক্ট.আর্টিকেলস / ১১১১65৮৮/২ পোস্ট করেছেন এমন এক্সপ্রেশন ট্রি ব্যবহার করে ক্লোনিং কোড , একটি সুরক্ষা ব্যতিক্রম সহ নেট ফ্রেমওয়ার্কের নতুন সংস্করণে ব্যর্থ হচ্ছে, অপারেশন রানটাইমকে অস্থিতিশীল করতে পারে , এটি মূলত ত্রুটিযুক্ত অভিব্যক্তি গাছের কারণে ব্যতিক্রম, যা রানটাইমের সময় ফানক তৈরি করতে ব্যবহৃত হয়, দয়া করে আপনার কিছু সমাধান আছে কিনা তা পরীক্ষা করে দেখুন n বাস্তবে আমি কেবল গভীর শ্রেণিবিন্যাসের সাথে জটিল বিষয়গুলিই দেখেছি, সহজ একটি অনুলিপি করা যায়
মৃণাল কাম্বোজ

1
এক্সপ্রেশনট্রি বাস্তবায়ন খুব ভাল বলে মনে হচ্ছে। এমনকি এটি বিজ্ঞপ্তি সংক্রান্ত রেফারেন্স এবং ব্যক্তিগত সদস্যদের সাথেও কাজ করে। কোনও বৈশিষ্ট্যের প্রয়োজন নেই। আমি খুঁজে পেয়েছি সেরা উত্তর।
N73k

সেরা উত্তর, খুব ভাল কাজ করেছে, আপনি আমার দিন বাঁচিয়েছেন
আদেল মুরাদ

23

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

আইক্লোনেবল ব্যবহার করে ক্লোনিং সম্পর্কিত আরও বিশদ ব্যাখ্যার জন্য এই নিবন্ধটি দেখুন

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

আরও কয়েকটি বিকল্পের জন্য এই বিকাশকারীর কর্নার নিবন্ধটি দেখুন (আইয়ানকে ক্রেডিট)।


1
আইসিএলনেবলের জেনেরিক ইন্টারফেস নেই, সুতরাং সেই ইন্টারফেসটি ব্যবহার করার পরামর্শ দেওয়া হয় না।
কার্গ

আপনার সমাধানটি বিজ্ঞপ্তি সংক্রান্ত রেফারেন্সগুলি পরিচালনা করতে না হওয়া পর্যন্ত কাজ করে, তারপরে জিনিসগুলি জটিল হওয়া শুরু করে, গভীর সিরিয়ালাইজেশন ব্যবহার করে গভীর ক্লোনিং প্রয়োগ করার চেষ্টা করা আরও ভাল।
পপ ক্যাটালিন

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

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

চিয়ার্স।


4
আইসিএলনেবলের জেনেরিক ইন্টারফেস নেই, সুতরাং সেই ইন্টারফেসটি ব্যবহার করার পরামর্শ দেওয়া হয় না।
কার্গ

সহজ এবং সংক্ষিপ্ত উত্তরগুলি সেরা।
ডেভিডগুইটা

17

সম্পাদনা: প্রকল্পটি বন্ধ রয়েছে

আপনি যদি অজানা ধরণের কাছে সত্যিকারের ক্লোনিং করতে চান তবে আপনি ফাস্টক্লোনটি একবার দেখে নিতে পারেন ।

এটি এক্সপ্রেশন ভিত্তিক ক্লোনিং বাইনারি সিরিয়ালাইজেশন এবং সম্পূর্ণ বস্তুর গ্রাফ অখণ্ডতা বজায় রাখার চেয়ে প্রায় 10 গুণ বেশি দ্রুত কাজ করে।

এর অর্থ: আপনি যদি আপনার হায়রাচিতে একই জিনিসটিতে একাধিকবার উল্লেখ করেন তবে ক্লোনটিতে একটি মৌমাছি রেফারেন্স রেফারেন্সও থাকবে।

ক্লোন করা অবজেক্টগুলিতে ইন্টারফেস, অ্যাট্রিবিউট বা অন্য কোনও পরিবর্তনের দরকার নেই।


এটি বেশ কার্যকর বলে মনে হচ্ছে
লাকলিইকি

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

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

আমি এটি চেষ্টা করেছিলাম এবং এটি আমার পক্ষে মোটেও কার্যকর হয়নি। একটি সদস্যঅ্যাক্সেস ব্যতিক্রম নিক্ষেপ।
মাইকেল ব্রাউন 22

এটি নেট এর নতুন সংস্করণগুলির সাথে কাজ করে না এবং বন্ধ হয়ে যায়
মাইকেল স্যান্ডার

14

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

MyType source = new MyType();
Mapper.CreateMap<MyType, MyType>();
MyType target = Mapper.Map<MyType, MyType>(source);

লক্ষ্য বস্তু এখন উত্স অবজেক্টের একটি অনুলিপি। যথেষ্ট সহজ না? আপনার সমাধানের সর্বত্র ব্যবহার করার জন্য একটি এক্সটেনশন পদ্ধতি তৈরি করুন:

public static T Copy<T>(this T source)
{
    T copy = default(T);
    Mapper.CreateMap<T, T>();
    copy = Mapper.Map<T, T>(source);
    return copy;
}

এক্সটেনশন পদ্ধতিটি অনুসরণ হিসাবে ব্যবহার করা যেতে পারে:

MyType copy = source.Copy();

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

1
এটি কেবল অগভীর অনুলিপি করে।
N73k

11

আমি নিজেই একটি অনুলিপি তালিকা <টি> প্রস্তুত করার জন্য একটি নেট নেট অভাবকে অতিক্রম করার জন্য এটি নিয়ে এসেছি ।

আমি এটি ব্যবহার:

static public IEnumerable<SpotPlacement> CloneList(List<SpotPlacement> spotPlacements)
{
    foreach (SpotPlacement sp in spotPlacements)
    {
        yield return (SpotPlacement)sp.Clone();
    }
}

এবং অন্য জায়গায়:

public object Clone()
{
    OrderItem newOrderItem = new OrderItem();
    ...
    newOrderItem._exactPlacements.AddRange(SpotPlacement.CloneList(_exactPlacements));
    ...
    return newOrderItem;
}

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

আরও ভাল, জেনেরিক তালিকা ব্যবহার করুন <T> ক্লোনার:

class Utility<T> where T : ICloneable
{
    static public IEnumerable<T> CloneList(List<T> tl)
    {
        foreach (T t in tl)
        {
            yield return (T)t.Clone();
        }
    }
}

10

প্র: আমি কেন এই উত্তরটি বেছে নেব?

  • আপনি যদি দ্রুততম গতি চান তবে এই উত্তরটি চয়ন করুন N নেট সক্ষম।
  • আপনি যদি ক্লোনিংয়ের সত্যিই, সত্যই একটি সহজ পদ্ধতি চান তবে এই উত্তরটিকে উপেক্ষা করুন।

অন্য কথায়, যদি আপনার কোনও পারফরম্যান্স বাধা না থাকে তবে অন্য উত্তরের সাথে যান , যদি না আপনি ফিক্সিংয়ের প্রয়োজন হয় এবং আপনি এটি প্রোফাইলার দিয়ে প্রমাণ করতে পারবেন না

অন্যান্য পদ্ধতির তুলনায় 10x দ্রুত

গভীর ক্লোন সম্পাদন করার জন্য নিম্নলিখিত পদ্ধতিটি হ'ল:

  • সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশন জড়িত যে কোনও কিছু থেকে 10x দ্রুত;
  • তাত্ত্বিক সর্বাধিক গতির কাছে খুব সুন্দর রঙিন। নেট সক্ষম is

এবং পদ্ধতি ...

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

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

এখানে কোডের আউটপুট 100,000 ক্লোনগুলির জন্য তুলনামূলক পারফরম্যান্স দেখায়:

  • নেস্টেড স্ট্রাইভস স্ট্রাইক-তে নেস্টেড মেম্বারওয়াই ক্লোন এর জন্য 1.08 সেকেন্ড
  • নেস্টেড মেম্বারওয়াই ক্লোনসের জন্য নেস্টেড ক্লাসে 4.77 সেকেন্ড
  • সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশনের জন্য 39.93 সেকেন্ড

কোনও কাঠামো অনুলিপি করার মতো ক্লাসে নেস্টেড মেম্বারসাই ক্লোন ব্যবহার করা এবং স্ট্রাক্ট অনুলিপি করা তাত্ত্বিক সর্বোচ্চ গতির কাছাকাছি খুব সুন্দর রঙিন। নেট সক্ষম।

Demo 1 of shallow and deep copy, using classes and MemberwiseClone:
  Create Bob
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Clone Bob >> BobsSon
  Adjust BobsSon details
    BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Elapsed time: 00:00:04.7795670,30000000

Demo 2 of shallow and deep copy, using structs and value copying:
  Create Bob
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Clone Bob >> BobsSon
  Adjust BobsSon details:
    BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Elapsed time: 00:00:01.0875454,30000000

Demo 3 of deep copy, using class and serialize/deserialize:
  Elapsed time: 00:00:39.9339425,30000000

সদস্যপদার্থকপি ব্যবহার করে কীভাবে একটি অনুলিপি করা যায় তা বুঝতে, এখানে ডেমো প্রকল্পটি যা উপরের সময়গুলি তৈরি করতে ব্যবহৃত হয়েছিল:

// Nested MemberwiseClone example. 
// Added to demo how to deep copy a reference class.
[Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.
public class Person
{
    public Person(int age, string description)
    {
        this.Age = age;
        this.Purchase.Description = description;
    }
    [Serializable] // Not required if using MemberwiseClone
    public class PurchaseType
    {
        public string Description;
        public PurchaseType ShallowCopy()
        {
            return (PurchaseType)this.MemberwiseClone();
        }
    }
    public PurchaseType Purchase = new PurchaseType();
    public int Age;
    // Add this if using nested MemberwiseClone.
    // This is a class, which is a reference type, so cloning is more difficult.
    public Person ShallowCopy()
    {
        return (Person)this.MemberwiseClone();
    }
    // Add this if using nested MemberwiseClone.
    // This is a class, which is a reference type, so cloning is more difficult.
    public Person DeepCopy()
    {
            // Clone the root ...
        Person other = (Person) this.MemberwiseClone();
            // ... then clone the nested class.
        other.Purchase = this.Purchase.ShallowCopy();
        return other;
    }
}
// Added to demo how to copy a value struct (this is easy - a deep copy happens by default)
public struct PersonStruct
{
    public PersonStruct(int age, string description)
    {
        this.Age = age;
        this.Purchase.Description = description;
    }
    public struct PurchaseType
    {
        public string Description;
    }
    public PurchaseType Purchase;
    public int Age;
    // This is a struct, which is a value type, so everything is a clone by default.
    public PersonStruct ShallowCopy()
    {
        return (PersonStruct)this;
    }
    // This is a struct, which is a value type, so everything is a clone by default.
    public PersonStruct DeepCopy()
    {
        return (PersonStruct)this;
    }
}
// Added only for a speed comparison.
public class MyDeepCopy
{
    public static T DeepCopy<T>(T obj)
    {
        object result = null;
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
            result = (T)formatter.Deserialize(ms);
            ms.Close();
        }
        return (T)result;
    }
}

তারপরে, প্রধান থেকে ডেমো কল করুন:

void MyMain(string[] args)
{
    {
        Console.Write("Demo 1 of shallow and deep copy, using classes and MemberwiseCopy:\n");
        var Bob = new Person(30, "Lamborghini");
        Console.Write("  Create Bob\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Console.Write("  Clone Bob >> BobsSon\n");
        var BobsSon = Bob.DeepCopy();
        Console.Write("  Adjust BobsSon details\n");
        BobsSon.Age = 2;
        BobsSon.Purchase.Description = "Toy car";
        Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
        Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Debug.Assert(Bob.Age == 30);
        Debug.Assert(Bob.Purchase.Description == "Lamborghini");
        var sw = new Stopwatch();
        sw.Start();
        int total = 0;
        for (int i = 0; i < 100000; i++)
        {
            var n = Bob.DeepCopy();
            total += n.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
    }
    {               
        Console.Write("Demo 2 of shallow and deep copy, using structs:\n");
        var Bob = new PersonStruct(30, "Lamborghini");
        Console.Write("  Create Bob\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Console.Write("  Clone Bob >> BobsSon\n");
        var BobsSon = Bob.DeepCopy();
        Console.Write("  Adjust BobsSon details:\n");
        BobsSon.Age = 2;
        BobsSon.Purchase.Description = "Toy car";
        Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
        Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);                
        Debug.Assert(Bob.Age == 30);
        Debug.Assert(Bob.Purchase.Description == "Lamborghini");
        var sw = new Stopwatch();
        sw.Start();
        int total = 0;
        for (int i = 0; i < 100000; i++)
        {
            var n = Bob.DeepCopy();
            total += n.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
    }
    {
        Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n");
        int total = 0;
        var sw = new Stopwatch();
        sw.Start();
        var Bob = new Person(30, "Lamborghini");
        for (int i = 0; i < 100000; i++)
        {
            var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);
            total += BobsSon.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n", sw.Elapsed, total);
    }
    Console.ReadKey();
}

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

মান প্রকারের বনাম রেফারেন্স প্রকার

মনে রাখবেন যে যখন কোনও বস্তুর ক্লোনিংয়ের বিষয়টি আসে তখন " স্ট্রাক্ট " এবং " শ্রেণি " এর মধ্যে একটি বড় পার্থক্য থাকে :

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

মান ধরণের এবং রেফারেন্সের ধরণের মধ্যে পার্থক্য দেখুন ।

ডিবাগিংয়ে সহায়তা করার জন্য চেকসামগুলি

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

অন্যান্য অনেক থ্রেড থেকে অনেক থ্রেড decoupling জন্য সত্যই দরকারী

এই কোডটির জন্য একটি দুর্দান্ত ব্যবহারের ক্ষেত্র হ'ল উত্পাদক / গ্রাহক নিদর্শন বাস্তবায়নের জন্য নেস্টেড শ্রেণীর ক্লোনগুলি খাওয়ানো বা একটি সারিতে স্ট্রাকচার।

  • আমাদের কাছে একটি (বা আরও) থ্রেড থাকতে পারে তারা নিজের মালিকানাধীন একটি ক্লাসটি পরিবর্তন করতে পারে, তারপরে এই শ্রেণীর একটি সম্পূর্ণ অনুলিপি এ তে ঠেলে দেয় ConcurrentQueue
  • আমাদের তখন এই ক্লাসগুলির অনুলিপিগুলি টানতে এবং তাদের সাথে ডিল করার জন্য একটি (বা আরও) থ্রেড রয়েছে।

এটি অনুশীলনে চূড়ান্তভাবে কাজ করে এবং আমাদের এক বা একাধিক থ্রেড (গ্রাহক) থেকে বহু থ্রেড (প্রযোজক) ডিকুয়াল করার অনুমতি দেয়।

এবং এই পদ্ধতিটি অন্ধভাবে দ্রুতও: আমরা যদি নেস্টেড স্ট্রিং ব্যবহার করি তবে এটি নেস্টেড ক্লাসগুলিকে সিরিয়ালাইজেশন / ডিসাইরিয়ালাইজড করার চেয়ে 35x দ্রুত এবং আমাদের মেশিনে উপলব্ধ সমস্ত থ্রেডের সুবিধা নিতে দেয়।

হালনাগাদ

স্পষ্টতই, এক্সপ্রেসপ্যাপার উপরের মতো হ্যান্ড কোডিংয়ের চেয়ে দ্রুত, যদি দ্রুত না হয়। আমাকে দেখতে হবে তারা কীভাবে একজন প্রোফাইকারের সাথে তুলনা করে।


আপনি যদি কোনও কাঠামো অনুলিপি করেন তবে অগভীর অনুলিপি পেতে পারেন, গভীর কপির জন্য আপনার এখনও নির্দিষ্ট প্রয়োগের প্রয়োজন হতে পারে।
লাসে ভি কার্লসেন

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

9

সাধারণভাবে, আপনি ICloneable ইন্টারফেস বাস্তবায়ন এবং নিজেকে ক্লোন বাস্তবায়ন। সি # অবজেক্টগুলির একটি বিল্ট-ইন মেমসারওয়াই ক্লোন পদ্ধতি রয়েছে যা একটি অগভীর অনুলিপি সম্পাদন করে যা আপনাকে সমস্ত আদিমদের জন্য সহায়তা করতে পারে।

গভীর অনুলিপিটির জন্য, এটি স্বয়ংক্রিয়ভাবে কীভাবে করা যায় তা জানার উপায় নেই।


আইসিএলনেবলের জেনেরিক ইন্টারফেস নেই, সুতরাং সেই ইন্টারফেসটি ব্যবহার করার পরামর্শ দেওয়া হয় না।
কার্গ

8

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


8

এখানে একটি গভীর অনুলিপি বাস্তবায়ন:

public static object CloneObject(object opSource)
{
    //grab the type and create a new instance of that type
    Type opSourceType = opSource.GetType();
    object opTarget = CreateInstanceOfType(opSourceType);

    //grab the properties
    PropertyInfo[] opPropertyInfo = opSourceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    //iterate over the properties and if it has a 'set' method assign it from the source TO the target
    foreach (PropertyInfo item in opPropertyInfo)
    {
        if (item.CanWrite)
        {
            //value types can simply be 'set'
            if (item.PropertyType.IsValueType || item.PropertyType.IsEnum || item.PropertyType.Equals(typeof(System.String)))
            {
                item.SetValue(opTarget, item.GetValue(opSource, null), null);
            }
            //object/complex types need to recursively call this method until the end of the tree is reached
            else
            {
                object opPropertyValue = item.GetValue(opSource, null);
                if (opPropertyValue == null)
                {
                    item.SetValue(opTarget, null, null);
                }
                else
                {
                    item.SetValue(opTarget, CloneObject(opPropertyValue), null);
                }
            }
        }
    }
    //return the new item
    return opTarget;
}

2
Memberwise ক্লোন মত এই সৌন্দর্য কারণ রেফারেন্স টাইপ বৈশিষ্ট্য সচেতন না
SLL

1
আপনি যদি অন্ধভাবে দ্রুত পারফরম্যান্স চান, তবে এই বাস্তবায়নের জন্য যাবেন না: এটি প্রতিবিম্ব ব্যবহার করে, সুতরাং এটি এত দ্রুত হবে না। বিপরীতভাবে, "অকাল অপ্টিমাইজেশন হ'ল সমস্ত মন্দ", সুতরাং আপনি প্রোফাইলার চালানোর পরে পর্যন্ত পারফরম্যান্সের দিকটি উপেক্ষা করুন।
কনটাঙ্গো

1
ক্রিয়েটিস্ট্যান্সঅফটাইপ সংজ্ঞায়িত হয় না?
মনস্টার এমএমআরপিজি

এটি পূর্ণসংখ্যায় ব্যর্থ হয়: "অ স্থির পদ্ধতির জন্য একটি লক্ষ্য প্রয়োজন" "
মিঃবি

8

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

https://github.com/kalisohn/CloneBehave

নুগেট প্যাকেজ হিসাবেও উপলব্ধ: https://www.nuget.org/packages/Clone.Behave/1.0.0

উদাহরণস্বরূপ: নীচের কোডটি ডিপক্লোন ঠিকানাটি করবে, তবে কেবলমাত্র_সামান্যজব ক্ষেত্রের অগভীর অনুলিপি সম্পাদন করবে।

public class Person 
{
  [DeepClone(DeepCloneBehavior.Shallow)]
  private Job _currentJob;      

  public string Name { get; set; }

  public Job CurrentJob 
  { 
    get{ return _currentJob; }
    set{ _currentJob = value; }
  }

  public Person Manager { get; set; }
}

public class Address 
{      
  public Person PersonLivingHere { get; set; }
}

Address adr = new Address();
adr.PersonLivingHere = new Person("John");
adr.PersonLivingHere.BestFriend = new Person("James");
adr.PersonLivingHere.CurrentJob = new Job("Programmer");

Address adrClone = adr.Clone();

//RESULT
adr.PersonLivingHere == adrClone.PersonLivingHere //false
adr.PersonLivingHere.Manager == adrClone.PersonLivingHere.Manager //false
adr.PersonLivingHere.CurrentJob == adrClone.PersonLivingHere.CurrentJob //true
adr.PersonLivingHere.CurrentJob.AnyProperty == adrClone.PersonLivingHere.CurrentJob.AnyProperty //true

7

উৎপাদকের কোড

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

আপনার যা দরকার তা হ'ল আংশিক শ্রেণীর সংজ্ঞা ICloneableএবং জেনারেটর বাকীটি করে:

public partial class Root : ICloneable
{
    public Root(int number)
    {
        _number = number;
    }
    private int _number;

    public Partial[] Partials { get; set; }

    public IList<ulong> Numbers { get; set; }

    public object Clone()
    {
        return Clone(true);
    }

    private Root()
    {
    }
} 

public partial class Root
{
    public Root Clone(bool deep)
    {
        var copy = new Root();
        // All value types can be simply copied
        copy._number = _number; 
        if (deep)
        {
            // In a deep clone the references are cloned 
            var tempPartials = new Partial[Partials.Length];
            for (var i = 0; i < Partials.Length; i++)
            {
                var value = Partials[i];
                value = value.Clone(true);
                tempPartials[i] = value;
            }
            copy.Partials = tempPartials;
            var tempNumbers = new List<ulong>(Numbers.Count);
            for (var i = 0; i < Numbers.Count; i++)
            {
                var value = Numbers[i];
                tempNumbers.Add(value);
            }
            copy.Numbers = tempNumbers;
        }
        else
        {
            // In a shallow clone only references are copied
            copy.Partials = Partials; 
            copy.Numbers = Numbers; 
        }
        return copy;
    }
}

দ্রষ্টব্য: সর্বশেষ সংস্করণে আরও নাল চেক রয়েছে, তবে আমি আরও ভাল বোঝার জন্য এগুলি ছেড়ে দিয়েছি।


6

আমি কপিরাইটস্ট্রাক্টরগুলিকে পছন্দ করি:

    public AnyObject(AnyObject anyObject)
    {
        foreach (var property in typeof(AnyObject).GetProperties())
        {
            property.SetValue(this, property.GetValue(anyObject));
        }
        foreach (var field in typeof(AnyObject).GetFields())
        {
            field.SetValue(this, field.GetValue(anyObject));
        }
    }

আপনার কাছে অনুলিপি করার জন্য আরও জিনিস রয়েছে


6

এই পদ্ধতিটি আমার জন্য সমস্যার সমাধান করেছে:

private static MyObj DeepCopy(MyObj source)
        {

            var DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

            return JsonConvert.DeserializeObject<MyObj >(JsonConvert.SerializeObject(source), DeserializeSettings);

        }

এটি এর মতো ব্যবহার করুন: MyObj a = DeepCopy(b);


6

সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশন সম্পর্কিত রিলে না ছাড়াই এখানে দ্রুত এবং সহজ সমাধান আমার জন্য কাজ করেছে।

public class MyClass
{
    public virtual MyClass DeepClone()
    {
        var returnObj = (MyClass)MemberwiseClone();
        var type = returnObj.GetType();
        var fieldInfoArray = type.GetRuntimeFields().ToArray();

        foreach (var fieldInfo in fieldInfoArray)
        {
            object sourceFieldValue = fieldInfo.GetValue(this);
            if (!(sourceFieldValue is MyClass))
            {
                continue;
            }

            var sourceObj = (MyClass)sourceFieldValue;
            var clonedObj = sourceObj.DeepClone();
            fieldInfo.SetValue(returnObj, clonedObj);
        }
        return returnObj;
    }
}

সম্পাদনা : প্রয়োজন

    using System.Linq;
    using System.Reflection;

আমি এটি ব্যবহার করেছিলাম কিভাবে

public MyClass Clone(MyClass theObjectIneededToClone)
{
    MyClass clonedObj = theObjectIneededToClone.DeepClone();
}

5

এই পদক্ষেপগুলি অনুসরণ করুন:

  • একটি নির্ধারণ ISelf<T>শুধুমাত্র পাঠযোগ্য সঙ্গে Selfসম্পত্তি যে আয় T, এবং ICloneable<out T>যার থেকে উদ্ভব ISelf<T>এবং একটি পদ্ধতি রয়েছে T Clone()
  • তারপর একটি সংজ্ঞায়িত CloneBaseটাইপ যা প্রয়োগ protected virtual generic VirtualCloneঢালাই MemberwiseCloneপাস-ইন টাইপ।
  • প্রতিটি উদ্ভূত প্রকারের VirtualCloneবেস ক্লোন পদ্ধতিটি কল করে এবং তারপরে অভিজাত ভার্চুয়ালক্লোন পদ্ধতিটি এখনও পরিচালনা করেনি এমন উদ্ভূত ধরণের দিকগুলি সঠিকভাবে ক্লোন করার জন্য যা করা দরকার তা করা উচিত।

সর্বাধিক উত্তরাধিকার বহুমুখিতা জন্য, ক্লোনিংয়ের কার্যক্ষমতা প্রকাশকারী ক্লাসগুলি হওয়া উচিত sealedতবে ক্লোনিংয়ের অভাব ব্যতীত অভিন্ন মত বেস ক্লাস থেকে নেওয়া উচিত । সুস্পষ্ট ক্লোনযোগ্য টাইপের ভেরিয়েবলগুলি পাস করার পরিবর্তে টাইপের একটি প্যারামিটার নিন ICloneable<theNonCloneableType>। এটি এমন একটি রুটিনকে অনুমতি দেবে যা ক্লোনযোগ্য ডেরাইভেটিভ এর ক্লোনযোগ্য ডেরিভেটিভের Fooসাথে কাজ করার প্রত্যাশা করে DerivedFoo, তবে এর অ-ক্লোনযোগ্য ডেরিভেটিভস তৈরির অনুমতি দেয় Foo



4

আমি স্বীকৃত উত্তরের একটি সংস্করণ তৈরি করেছি যা '[সিরিয়ালাইজেবল]' এবং '[ডেটা কনট্র্যাক্ট]' উভয়ের সাথেই কাজ করে। আমি এটি লেখার পরে অনেকক্ষণ হয়ে গেছে, তবে আমি যদি সঠিকভাবে মনে করি তবে [ডেটা কনট্রাক্ট] এর জন্য আলাদা সিরিয়ালাইজারের প্রয়োজন ছিল।

সিস্টেম, সিস্টেম.আইও, সিস্টেম.রুনটাইম.সিরিয়ালাইজেশন, সিস্টেম.রুনটাইম.সরিয়ালাইজেশন.ফর্ম্যাটটার্স.বাইনারি, সিস্টেম.এক্সএমএল প্রয়োজন ;

public static class ObjectCopier
{

    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[Serializable]' or '[DataContract]'
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (typeof(T).IsSerializable == true)
        {
            return CloneUsingSerializable<T>(source);
        }

        if (IsDataContract(typeof(T)) == true)
        {
            return CloneUsingDataContracts<T>(source);
        }

        throw new ArgumentException("The type must be Serializable or use DataContracts.", "source");
    }


    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[Serializable]'
    /// </summary>
    /// <remarks>
    /// Found on http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp
    /// Uses code found on CodeProject, which allows free use in third party apps
    /// - http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
    /// </remarks>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T CloneUsingSerializable<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }


    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[DataContract]'
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T CloneUsingDataContracts<T>(T source)
    {
        if (IsDataContract(typeof(T)) == false)
        {
            throw new ArgumentException("The type must be a data contract.", "source");
        }

        // ** Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        DataContractSerializer dcs = new DataContractSerializer(typeof(T));
        using(Stream stream = new MemoryStream())
        {
            using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
            {
                dcs.WriteObject(writer, source);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
                {
                    return (T)dcs.ReadObject(reader);
                }
            }
        }
    }


    /// <summary>
    /// Helper function to check if a class is a [DataContract]
    /// </summary>
    /// <param name="type">The type of the object to check.</param>
    /// <returns>Boolean flag indicating if the class is a DataContract (true) or not (false) </returns>
    public static bool IsDataContract(Type type)
    {
        object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);
        return attributes.Length == 1;
    }

} 

4

ঠিক আছে, এই পোস্টে প্রতিবিম্ব সহ কিছু সুস্পষ্ট উদাহরণ রয়েছে, তবে আপনি যথাযথভাবে ক্যাশে করা শুরু না করা পর্যন্ত তবে প্রতিচ্ছবি সাধারণত ধীর হয়।

যদি আপনি এটি যথাযথভাবে ক্যাশে করেন তবে এটি 4,6 এস (ওয়াচারের দ্বারা পরিমাপ করা) দ্বারা 1000000 অবজেক্টটি গভীরভাবে ক্লোন করে দেবে।

static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();

আপনি ক্যাশেড প্রোপার্টি নেওয়ার চেয়ে বা অভিধানে নতুন যুক্ত করার চেয়ে এগুলি সহজভাবে ব্যবহার করুন

foreach (var prop in propList)
{
        var value = prop.GetValue(source, null);   
        prop.SetValue(copyInstance, value, null);
}

অন্য একটি উত্তর আমার পোস্টে সম্পূর্ণ কোড চেক

https://stackoverflow.com/a/34365709/4711853


2
কল prop.GetValue(...)করা এখনও প্রতিবিম্বিত এবং ক্যাশে করা যায় না। একটি এক্সপ্রেশন ট্রিতে এটি যদিও এত তাড়াতাড়ি সংকলিত হয়েছে
সেং

4

যেহেতু এই প্রশ্নের প্রায় সমস্ত উত্তর অসন্তুষ্টিজনক হয়েছে বা স্পষ্টভাবে আমার পরিস্থিতিতে কাজ করে না, তাই আমি এ্যানিক্লোন রচনা করেছি যা প্রতিফলনের সাথে পুরোপুরি প্রয়োগ করা হয় এবং এখানে সমস্ত প্রয়োজনীয়তার সমাধান করে solved জটিল কাঠামোযুক্ত জটিল দৃশ্যে কাজ করার জন্য সিরিয়ালাইজেশন পেতে আমি অক্ষম ছিলাম এবং IClonableআদর্শের চেয়েও কম - আসলে এটি এমনকি প্রয়োজনীয় হওয়া উচিত নয়।

স্ট্যান্ডার্ড উপেক্ষা বৈশিষ্ট্যাবলী ব্যবহার সমর্থিত [IgnoreDataMember], [NonSerialized]। জটিল সংগ্রহ, সেটার ছাড়াই সম্পত্তি, পঠনযোগ্য ক্ষেত্র ইত্যাদি সমর্থন করে

আমি আশা করি এটি আমার অন্য কারও সাথে যারা একই সমস্যায় পড়েছিল তাদের সহায়তা করবে।


4

দাবি অস্বীকার: আমি উল্লিখিত প্যাকেজের লেখক।

আমি অবাক হয়েছিলাম যে 2019 সালে এই প্রশ্নের শীর্ষের উত্তরগুলি এখনও সিরিয়ালাইজেশন বা প্রতিবিম্ব ব্যবহার করে।

সিরিয়ালাইজেশন সীমাবদ্ধ করা হচ্ছে (বৈশিষ্ট্য, নির্দিষ্ট নির্মাণকারী ইত্যাদির প্রয়োজন) এবং এটি খুব ধীর

BinaryFormatterপ্রয়োজন Serializableগুণ, JsonConverterএকটি parameterless কন্সট্রাকটর বা বৈশিষ্ট্যাবলী প্রয়োজন, তন্ন তন্ন হ্যান্ডেল খুব ভাল শুধুমাত্র ক্ষেত্র বা ইন্টারফেসগুলি পড়া এবং উভয় 10-30x হয় প্রয়োজনীয় তুলনায় ধীর।

এক্সপ্রেশন গাছ

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

আমি নিজেই সমস্যার মুখোমুখি হয়েছি এবং সন্তোষজনক সমাধান না পেয়ে আমি এমন একটি প্যাকেজ তৈরি করার সিদ্ধান্ত নিয়েছি যা কেবল এটিই করে এবং প্রতিটি ধরণের সাথে কাজ করে এবং কাস্টম লিখিত কোডের মতো প্রায় দ্রুত

আপনি প্রকল্পটি গিটহাবটিতে খুঁজে পেতে পারেন: https://github.com/marseltoth/ObjectCloner

ব্যবহার

আপনি এটি নিউগেট থেকে ইনস্টল করতে পারেন। হয় ObjectClonerপ্যাকেজটি পান এবং এটি ব্যবহার করুন:

var clone = ObjectCloner.DeepClone(original);

অথবা যদি আপনি এক্সটেনশানগুলির সাথে আপনার অবজেক্টের ধরণের কলুষিত করতে আপত্তি করেন না ObjectCloner.Extensionsএবং লিখুন:

var clone = original.DeepClone();

কর্মক্ষমতা

ক্লাস হায়ারার্কির ক্লোনিংয়ের একটি সাধারণ মানদণ্ড প্রতিফলন ব্যবহারের চেয়ে ~ 3x দ্রুত, নিউটোনসফট.জসন সিরিয়ালাইজেশনের তুলনায় 12x faster দ্রুত এবং উচ্চ প্রস্তাবিতের চেয়ে ~ 36x দ্রুত দেখায় BinaryFormatter

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