c# - गहरी क्लोनिंग वस्तुओं




.net clone (20)

मैं कुछ ऐसा करना चाहता हूं:

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

और उसके बाद उस नई ऑब्जेक्ट में परिवर्तन करें जो मूल ऑब्जेक्ट में दिखाई नहीं दे रहा है।

मुझे अक्सर इस कार्यक्षमता की आवश्यकता नहीं होती है, इसलिए जब आवश्यक हो, तो मैंने एक नई वस्तु बनाने का प्रयास किया है और फिर प्रत्येक संपत्ति को अलग-अलग कॉपी किया है, लेकिन यह हमेशा मुझे इस भावना के साथ छोड़ देता है कि हैंडलिंग का एक बेहतर या अधिक सुरुचिपूर्ण तरीका है स्थिति।

मैं ऑब्जेक्ट को क्लोन या गहरी प्रतिलिपि कैसे बना सकता हूं ताकि क्लोन ऑब्जेक्ट को मूल ऑब्जेक्ट में दिखाई देने वाले किसी भी बदलाव के बिना संशोधित किया जा सके?

https://code.i-harness.com


Code Generator

We have seen a lot of ideas from serialization over manual implementation to reflection and I want to propose a totally different approach using the CGbR Code Generator . The generate clone method is memory and CPU efficient and therefor 300x faster as the standard DataContractSerializer.

All you need is a partial class definition with ICloneable and the generator does the rest:

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

Note: Latest version has a more null checks, but I left them out for better understanding.


Q. Why would I choose this answer?

  • Choose this answer if you want the fastest speed .NET is capable of.
  • Ignore this answer if you want a really, really easy method of cloning.

In other words, go with another answer unless you have a performance bottleneck that needs fixing, and you can prove it with a profiler .

10x faster than other methods

The following method of performing a deep clone is:

  • 10x faster than anything that involves serialization/deserialization;
  • Pretty darn close to the theoretical maximum speed .NET is capable of.

And the method ...

For ultimate speed, you can use Nested MemberwiseClone to do a deep copy . Its almost the same speed as copying a value struct, and is much faster than (a) reflection or (b) serialization (as described in other answers on this page).

Note that if you use Nested MemberwiseClone for a deep copy , you have to manually implement a ShallowCopy for each nested level in the class, and a DeepCopy which calls all said ShallowCopy methods to create a complete clone. This is simple: only a few lines in total, see the demo code below.

Here is the output of the code showing the relative performance difference for 100,000 clones:

  • 1.08 seconds for Nested MemberwiseClone on nested structs
  • 4.77 seconds for Nested MemberwiseClone on nested classes
  • 39.93 seconds for Serialization/Deserialization

Using Nested MemberwiseClone on a class almost as fast as copying a struct, and copying a struct is pretty darn close to the theoretical maximum speed .NET is capable of.

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

To understand how to do a deep copy using MemberwiseCopy, here is the demo project that was used to generate the times above:

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

Then, call the demo from main:

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

Again, note that if you use Nested MemberwiseClone for a deep copy , you have to manually implement a ShallowCopy for each nested level in the class, and a DeepCopy which calls all said ShallowCopy methods to create a complete clone. This is simple: only a few lines in total, see the demo code above.

Value types vs. References Types

Note that when it comes to cloning an object, there is is a big difference between a " struct " and a " class ":

  • If you have a " struct ", it's a value type so you can just copy it, and the contents will be cloned (but it will only make a shallow clone unless you use the techniques in this post).
  • If you have a " class ", it's a reference type , so if you copy it, all you are doing is copying the pointer to it. To create a true clone, you have to be more creative, and use differences between value types and references types which creates another copy of the original object in memory.

See differences between value types and references types .

Checksums to aid in debugging

  • Cloning objects incorrectly can lead to very difficult-to-pin-down bugs. In production code, I tend to implement a checksum to double check that the object has been cloned properly, and hasn't been corrupted by another reference to it. This checksum can be switched off in Release mode.
  • I find this method quite useful: often, you only want to clone parts of the object, not the entire thing.

Really useful for decoupling many threads from many other threads

One excellent use case for this code is feeding clones of a nested class or struct into a queue, to implement the producer / consumer pattern.

  • We can have one (or more) threads modifying a class that they own, then pushing a complete copy of this class into a ConcurrentQueue .
  • We then have one (or more) threads pulling copies of these classes out and dealing with them.

This works extremely well in practice, and allows us to decouple many threads (the producers) from one or more threads (the consumers).

And this method is blindingly fast too: if we use nested structs, it's 35x faster than serializing/deserializing nested classes, and allows us to take advantage of all of the threads available on the machine.

अद्यतन करें

Apparently, ExpressMapper is as fast, if not faster, than hand coding such as above. I might have to see how they compare with a profiler.


इन कदमों का अनुसरण करें:

  • Define an ISelf<T> with a read-only Self property that returns T , and ICloneable<out T> , which derives from ISelf<T> and includes a method T Clone() .
  • Then define a CloneBase type which implements a protected virtual generic VirtualClone casting MemberwiseClone to the passed-in type.
  • Each derived type should implement VirtualClone by calling the base clone method and then doing whatever needs to be done to properly clone those aspects of the derived type which the parent VirtualClone method hasn't yet handled.

For maximum inheritance versatility, classes exposing public cloning functionality should be sealed , but derive from a base class which is otherwise identical except for the lack of cloning. Rather than passing variables of the explicit clonable type, take a parameter of type ICloneable<theNonCloneableType> . This will allow a routine that expects a cloneable derivative of Foo to work with a cloneable derivative of DerivedFoo , but also allow the creation of non-cloneable derivatives of Foo .


खैर मुझे सिल्वरलाइट में आईसीएलनेबल का उपयोग करने में समस्याएं आ रही थीं, लेकिन मुझे क्रमबद्धता का विचार पसंद आया, मैं एक्सएमएल को क्रमबद्ध कर सकता हूं, इसलिए मैंने यह किया:

static public class SerializeHelper
{
    //Michael White, Holly Springs Consulting, 2009
    //[email protected]
    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);
    }
}

मैं एक क्लोन के लिए एक प्रतिलिपि निर्माता पसंद करते हैं। इरादा स्पष्ट है।


मैं मुख्य रूप से primitives और सूचियों की बहुत सरल वस्तुओं के लिए एक क्लोनर चाहता था। यदि आपका ऑब्जेक्ट JSON serializable बॉक्स से बाहर है तो यह विधि चाल करेगी। इसके लिए क्लोन क्लास पर इंटरफेस का कोई संशोधन या कार्यान्वयन की आवश्यकता नहीं है, केवल JSON.NET जैसे JSON serializer।

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

मैंने CloneExtensions लाइब्रेरी प्रोजेक्ट बनाया है। यह अभिव्यक्ति वृक्ष रनटाइम कोड संकलन द्वारा उत्पन्न सरल असाइनमेंट ऑपरेशंस का उपयोग करके तेज़, गहरे क्लोन का प्रदर्शन करता है।

इसका इस्तेमाल कैसे करें?

फ़ील्ड और गुणों के बीच असाइनमेंट के स्वर के साथ अपने स्वयं के Clone या Copy विधियों को लिखने के बजाय प्रोग्राम अभिव्यक्ति वृक्ष का उपयोग करके स्वयं को अपने लिए करते हैं। एक्सटेंशन विधि के रूप में चिह्नित GetClone<T>() विधि आपको इसे अपने उदाहरण पर कॉल करने की अनुमति देती है:

var newInstance = source.GetClone();

newInstance का उपयोग करके आप source से newInstance प्रतिलिपि बनाई जानी चाहिए चुन सकते हैं:

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

क्या क्लोन किया जा सकता है?

  • आदिम (int, uint, बाइट, डबल, चार, आदि), ज्ञात अपरिवर्तनीय प्रकार (डेटटाइम, टाइमस्पैन, स्ट्रिंग) और प्रतिनिधियों (एक्शन, फनक इत्यादि सहित)
  • नल
  • टी [] सरणी
  • जेनेरिक वर्गों और structs सहित कस्टम वर्गों और structs।

निम्नलिखित वर्ग / संरचना सदस्यों को आंतरिक रूप से क्लोन किया जाता है:

  • जनता के मूल्य, न केवल पढ़े क्षेत्र
  • दोनों संपत्तियों के साथ सार्वजनिक गुणों के मूल्य प्राप्त करें और सेट करें
  • ICollection लागू करने के प्रकार के लिए संग्रह आइटम

यह कितना तेज़ है?

समाधान तेजी से प्रतिबिंब है, क्योंकि सदस्यों की जानकारी केवल एक बार इकट्ठी की जानी चाहिए, GetClone<T> पहले दिए गए प्रकार T लिए पहली बार उपयोग किया जाता है।

यह serialization- आधारित समाधान से भी तेज़ है जब आप एक ही प्रकार के T कुछ उदाहरणों को क्लोन करते हैं।

और अधिक...

documentation पर उत्पन्न अभिव्यक्तियों के बारे में और पढ़ें।

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

क्या यह बिल्कुल नहीं है कि आप List<int> लिए अपनी Clone विधि कैसे लिखेंगे?


यदि आप अज्ञात प्रकारों के लिए सही क्लोनिंग चाहते हैं तो आप fastclone पर एक नज़र fastclone

यह अभिव्यक्ति आधारित क्लोनिंग द्विआधारी क्रमिकरण से लगभग 10 गुना तेजी से काम कर रही है और पूर्ण ऑब्जेक्ट ग्राफ़ अखंडता को बनाए रखती है।

इसका अर्थ है: यदि आप अपने पदानुक्रम में एक ही ऑब्जेक्ट में कई बार संदर्भित करते हैं, तो क्लोन में संदर्भित एक उदाहरण भी होगा।

क्लोन किए जा रहे वस्तुओं को इंटरफेस, विशेषताओं या किसी भी अन्य संशोधन की आवश्यकता नहीं है।


यहां जुड़े विकल्पों में से कई के बारे में बहुत कुछ पढ़ने के बाद, और इस मुद्दे के लिए संभावित समाधान, मेरा मानना ​​है कि इयान पी के लिंक पर सभी विकल्पों को संक्षेप में सारांशित किया गया है (अन्य सभी विकल्प उन में भिन्नताएं हैं) और सर्वोत्तम समाधान प्रदान किया जाता है प्रश्न टिप्पणियों पर agiledeveloper.com/articles/cloning072002.htm

तो मैं यहां उन 2 संदर्भों के प्रासंगिक भागों की प्रतिलिपि बनाउंगा। इस तरह हम कर सकते हैं:

सी तेज में वस्तुओं को क्लोन करने के लिए सबसे अच्छी बात है!

सबसे पहले और सबसे महत्वपूर्ण, ये हमारे सभी विकल्प हैं:

अभिव्यक्ति पेड़ द्वारा फास्ट डीप कॉपी लेख में सीरियलाइजेशन, रिफ्लेक्शन एंड एक्सप्रेशन पेड़ द्वारा क्लोनिंग की प्रदर्शन तुलना भी है।

मैं आईसीएलनेबल क्यों चुनता हूं (यानी मैन्युअल रूप से)

agiledeveloper.com/articles/cloning072002.htm

उनके सभी आलेख मंडल एक उदाहरण के आसपास हैं जो अधिकांश वस्तुओं के लिए लागू होने का प्रयास करते हैं, 3 वस्तुओं का उपयोग करते हुए: व्यक्ति , मस्तिष्क और शहर । हम एक व्यक्ति को क्लोन करना चाहते हैं, जिसका अपना मस्तिष्क होगा लेकिन एक ही शहर होगा। आप या तो उपरोक्त अन्य विधियों में से किसी भी समस्या को चित्र या पढ़ सकते हैं।

यह उनके निष्कर्ष का मेरा थोड़ा संशोधित संस्करण है:

क्लास नाम के बाद New निर्दिष्ट करके ऑब्जेक्ट की प्रतिलिपि बनाना अक्सर उस कोड की ओर जाता है जो एक्स्टेंसिबल नहीं है। क्लोन का उपयोग, प्रोटोटाइप पैटर्न का उपयोग, इसे प्राप्त करने का एक बेहतर तरीका है। हालांकि, क्लोन का उपयोग करके इसे सी # (और जावा) में प्रदान किया जाता है, यह भी काफी समस्याग्रस्त हो सकता है। एक संरक्षित (गैर-सार्वजनिक) प्रतिलिपि निर्माता प्रदान करना बेहतर है और क्लोन विधि से इसका आह्वान करना बेहतर है। यह हमें एक वर्ग के उदाहरण के लिए ऑब्जेक्ट बनाने का कार्य सौंपने की क्षमता देता है, इस प्रकार संरक्षित प्रतिलिपि बनाने वाले का उपयोग करके वस्तुओं को सुरक्षित रूप से और सुरक्षित रूप से प्रदान करता है।

उम्मीद है कि यह कार्यान्वयन चीजों को स्पष्ट कर सकता है:

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 [email protected]
This is person with [email protected]
SkilledPerson: This is person with [email protected]
SkilledPerson: This is person with [email protected]

ध्यान दें, अगर हम वस्तुओं की संख्या की गिनती रखते हैं, तो यहां लागू क्लोन वस्तुओं की संख्या की सही गणना रखेगा।


संक्षिप्त जवाब यह है कि आप आईसीएलनेबल इंटरफ़ेस से प्राप्त होते हैं और फिर .clone फ़ंक्शन को लागू करते हैं। क्लोन को सदस्यवार प्रतिलिपि करना चाहिए और किसी भी सदस्य पर गहरी प्रतिलिपि करना चाहिए जिसके लिए इसकी आवश्यकता होती है, फिर परिणामी वस्तु को वापस कर दें। यह एक पुनरावर्ती ऑपरेशन है (यह आवश्यक है कि जिस वर्ग को आप क्लोन करना चाहते हैं उसके सभी सदस्य या तो मूल्य प्रकार हैं या आईसीएलनेबल लागू करते हैं और उनके सदस्य या तो मूल्य प्रकार हैं या आईसीएलनेबल लागू करते हैं, और इसी तरह)।

आईसीएलनेबल का उपयोग करके क्लोनिंग पर एक और विस्तृत स्पष्टीकरण के लिए, इस आलेख को देखें

लंबा जवाब "यह निर्भर करता है"। जैसा कि दूसरों द्वारा उल्लेख किया गया है, आईसीएलनेबल जेनेरिक द्वारा समर्थित नहीं है, परिपत्र वर्ग संदर्भों के लिए विशेष विचारों की आवश्यकता है, और वास्तव में कुछ लोगों द्वारा .NET Framework में "गलती" के रूप में देखा जाता है। क्रमबद्धता विधि आपके ऑब्जेक्ट्स पर निर्भर करता है, जो वे नहीं हो सकते हैं और जिन पर आपका कोई नियंत्रण नहीं हो सकता है। समुदाय में अभी भी बहुत बहस है जिस पर "सर्वश्रेष्ठ" अभ्यास है। हकीकत में, समाधानों में से कोई भी एक आकार का आकार नहीं है, सभी स्थितियों के लिए आईसीएलनेबल मूल रूप से व्याख्या की गई थी।

कुछ डेवलपर (इयान के लिए क्रेडिट) के लिए इस डेवलपर का कॉर्नर आलेख देखें।


सभी सार्वजनिक संपत्तियों की प्रतिलिपि बनाने के लिए सरल विस्तार विधि। किसी भी वस्तु के लिए काम करता है और कक्षा [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 ) } );
        }
    };
}

ICloneable का उपयोग न करने का कारण यह नहीं है क्योंकि इसमें सामान्य इंटरफ़ेस नहीं है। इसका उपयोग करने का कारण यह नहीं है क्योंकि यह अस्पष्ट है । यह स्पष्ट नहीं करता है कि आपको उथले या गहरी प्रतिलिपि मिल रही है या नहीं; यह कार्यान्वयन करने के लिए है।

हां, MemberwiseClone एक उथली प्रतिलिपि बनाता है, लेकिन MemberwiseClone के विपरीत Clone नहीं है; यह शायद, DeepClone , जो अस्तित्व में नहीं है। जब आप अपने आईसीएलनेबल इंटरफ़ेस के माध्यम से किसी ऑब्जेक्ट का उपयोग करते हैं, तो आप यह नहीं जान सकते कि अंतर्निहित ऑब्जेक्ट किस प्रकार का क्लोनिंग करता है। (और एक्सएमएल टिप्पणियां इसे स्पष्ट नहीं कर पाएंगी, क्योंकि आपको ऑब्जेक्ट की क्लोन विधि के बजाय इंटरफ़ेस टिप्पणियां मिलेंगी।)

मैं आमतौर पर जो करता हूं वह एक Copy विधि बनाता है जो वही करता है जो मैं चाहता हूं।


Here a solution fast and easy that worked for me without relaying on Serialization/Deserialization.

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

EDIT : requires

    using System.Linq;
    using System.Reflection;

That's How I used it

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

Here is a deep copy implementation:

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

I like Copyconstructors like that:

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

If you have more things to copy add them


I think you can try this.

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = new MyObject(myObj); //DeepClone it

If your Object Tree is Serializeable you could also use something like this

static public MyClass Clone(MyClass myClass)
{
    MyClass clone;
    XmlSerializer ser = new XmlSerializer(typeof(MyClass), _xmlAttributeOverrides);
    using (var ms = new MemoryStream())
    {
        ser.Serialize(ms, myClass);
        ms.Position = 0;
        clone = (MyClass)ser.Deserialize(ms);
    }
    return clone;
}

be informed that this Solution is pretty easy but it's not as performant as other solutions may be.

And be sure that if the Class grows, there will still be only those fields cloned, which also get serialized.


In general, you implement the ICloneable interface and implement Clone yourself. C# objects have a built-in MemberwiseClone method that performs a shallow copy that can help you out for all the primitives.

For a deep copy, there is no way it can know how to automatically do it.


Ok, there are some obvious example with reflection in this post, BUT reflection is usually slow, until you start to cache it properly.

if you'll cache it properly, than it'll deep clone 1000000 object by 4,6s (measured by Watcher).

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

than you take cached properties or add new to dictionary and use them simply

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

full code check in my post in another answer

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


This method solved the problem for me:

private static MyObj DeepCopy(MyObj source)
        {

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

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

        }

Use it like this: MyObj a = DeepCopy(b);





clone