मैं सी # में एक सामान्य सूची कैसे क्लोन करूं?


592

मेरे पास C # में वस्तुओं की एक सामान्य सूची है, और सूची को क्लोन करना चाहते हैं। सूची के भीतर आइटम क्लोन करने योग्य हैं, लेकिन ऐसा करने का विकल्प नहीं लगता है list.Clone()

क्या इसके आसपास कोई आसान तरीका है?


44
आपको यह कहना चाहिए कि यदि आप एक गहरी प्रतिलिपि या एक उथली प्रतिलिपि की तलाश कर रहे हैं
नोव

10
गहरी और उथली प्रतियां क्या हैं?
कर्नल पैनिक


3
@orip clone()एक गहरी प्रति की परिभाषा से नहीं है? C # में आप आसानी से = के साथ पॉइंटर्स पास कर सकते हैं, मैंने सोचा।
क्रिस

13
@ क्रिस उथली प्रतिलिपि एक स्तर की प्रतिलिपि सूचक प्रतिलिपि की तुलना में गहरी है। उदाहरण के लिए किसी सूची की उथली प्रति में समान तत्व होंगे, लेकिन एक अलग सूची होगी।
orip

जवाबों:


385

आप एक एक्सटेंशन विधि का उपयोग कर सकते हैं।

static class Extensions
{
    public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
    {
        return listToClone.Select(item => (T)item.Clone()).ToList();
    }
}

71
मुझे लगता है कि List.ConvertAll यह तेजी से समय में कर सकता है, क्योंकि यह सूची के लिए पूरे सरणी को पूर्व-आवंटित कर सकता है, बनाम सभी समय का आकार बदलने के लिए।
माइकलजी

2
@MichaelGG, क्या होगा अगर आप कनवर्ट नहीं करना चाहते हैं लेकिन सूची में आइटमों को केवल क्लोन / डुप्लिकेट करें? क्या यह काम करेगा? || var clonedList = ListOfStrings.ConvertAll (p => p);
IbrarMumtaz

29
@IbrarMumtaz: यह var क्लोनडलिस्ट = नई सूची <string> (ListOffrings) के समान है;
ब्रैंडन अर्नाल्ड

4
अच्छा समाधान! वैसे मैं सार्वजनिक स्थैतिक सूची पसंद करता हूं <T> CLone <T> ... यह इस तरह के मामलों में अधिक उपयोगी है, क्योंकि किसी और कलाकार की आवश्यकता नहीं है: सूची <MyType> क्लोन = listToClone.Clone ();
प्लूटोज़

2
यह गहरी क्लोनिंग है
जॉर्ज बीरबिलिस

511

यदि आपके तत्व मूल्य प्रकार हैं, तो आप बस कर सकते हैं:

List<YourType> newList = new List<YourType>(oldList);

हालाँकि, यदि वे संदर्भ प्रकार हैं और आप एक गहरी प्रतिलिपि चाहते हैं (अपने तत्वों को ठीक से लागू करना ICloneable), तो आप ऐसा कुछ कर सकते हैं:

List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);

oldList.ForEach((item) =>
    {
        newList.Add((ICloneable)item.Clone());
    });

जाहिर है, ICloneableउपरोक्त जेनेरिक में बदलें और जो कुछ भी आपके तत्व प्रकार के साथ है वह लागू होता है ICloneable

यदि आपका तत्व प्रकार समर्थन नहीं करता है, ICloneableलेकिन प्रतिलिपि-निर्माता है, तो आप इसके बजाय ऐसा कर सकते हैं:

List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);

oldList.ForEach((item)=>
    {
        newList.Add(new YourType(item));
    });

व्यक्तिगत रूप से, मैं ICloneableसभी सदस्यों की गहरी प्रति की गारंटी देने की आवश्यकता के कारण से बचूंगा। इसके बजाय, मैं सुझाव दूंगा कि कॉपी-कंस्ट्रक्टर या फैक्ट्री मेथड जैसा YourType.CopyFrom(YourType itemToCopy)कोई नया उदाहरण देता है YourType

इनमें से कोई भी विकल्प एक विधि (विस्तार या अन्यथा) द्वारा लपेटा जा सकता है।


1
मुझे लगता है कि सूची <T> .ConvertAll एक नई सूची बनाने और एक फ़ॉर्वर्ड + जोड़ने की तुलना में अच्छे लग सकता है।
माइकल जीजी

2
@ दिमित्री: नहीं, यह सच नहीं है। समस्या यह है कि, जब ICloneableपरिभाषित किया गया था, तो परिभाषा ने कभी नहीं कहा कि क्या क्लोन गहरा था या उथला है, इसलिए आप यह निर्धारित नहीं कर सकते हैं कि जब कोई ऑब्जेक्ट इसे लागू करता है तो किस प्रकार का क्लोन ऑपरेशन किया जाएगा। इसका मतलब यह है कि यदि आप एक गहरी क्लोनिंग करना चाहते हैं List<T>, तो आपको यह ICloneableसुनिश्चित करने के बिना करना होगा कि यह एक गहरी कॉपी है।
जेफ़ येट्स

5
AddRange पद्धति का उपयोग क्यों नहीं किया जाता है? ( newList.AddRange(oldList.Select(i => i.Clone())या newList.AddRange(oldList.Select(i => new YourType(i))
phoog

5
@ फोटो: मुझे लगता है कि कोड को स्कैन करते समय यह थोड़ा कम पठनीय / समझने योग्य है, बस। मेरे लिए पठनीयता जीत गई।
जेफ येट्स

1
@ जेफयेट्स: एक अपर्याप्त रूप से मानी जाने वाली शिकन यह है कि चीजों को आम तौर पर केवल कॉपी करने की आवश्यकता होती है अगर कुछ निष्पादन पथ मौजूद होता है जो उन्हें उत्परिवर्तित करेगा। यह बहुत अपरिवर्तनीय प्रकार परिवर्तनशील प्रकार का एक उदाहरण के लिए एक संदर्भ पकड़ है, लेकिन कुछ भी है कि यह उत्परिवर्तित जाएगा कि उदाहरण का पर्दाफाश कभी नहीं आम। उन चीजों की अनावश्यक नकल जो कभी बदलने वाली नहीं हैं, कभी-कभी एक प्रमुख प्रदर्शन नाली हो सकती हैं, जो कि परिमाण के आदेशों द्वारा स्मृति के उपयोग को बढ़ाती है।
सुपरकैट

84

एक उथली प्रतिलिपि के लिए, आप इसके बजाय सामान्य सूची वर्ग के GetRange विधि का उपयोग कर सकते हैं।

List<int> oldList = new List<int>( );
// Populate oldList...

List<int> newList = oldList.GetRange(0, oldList.Count);

से उद्धृत: जेनरिक रेसिपी


43
आप सूची <T> के संदूक का उपयोग करके भी इसे प्राप्त कर सकते हैं सूची <T> जिसमें से कॉपी करना है। उदाहरण के लिए var उथले क्लोनडिस्ट = नई सूची <MyObject> (मूल सूची);
अर्किलिक्नाम

9
मैं अक्सर उपयोग करता हूं List<int> newList = oldList.ToList()। एक ही प्रभाव। हालांकि, मेरी राय में पठनीयता के लिए अरकिलिकम का समाधान सबसे अच्छा है।
दान बिक्रम

82
public static object DeepClone(object obj) 
{
  object objResult = null;
  using (MemoryStream  ms = new MemoryStream())
  {
    BinaryFormatter  bf =   new BinaryFormatter();
    bf.Serialize(ms, obj);

    ms.Position = 0;
    objResult = bf.Deserialize(ms);
  }
  return objResult;
}

यह C # और .NET 2.0 के साथ करने का एक तरीका है। आपकी वस्तु होना आवश्यक है [Serializable()]। लक्ष्य सभी संदर्भों को खोना और नए का निर्माण करना है।


11
+1 - मुझे यह जवाब पसंद है - यह त्वरित, गंदा, गंदा और बहुत प्रभावी है। मैंने सिल्वरलाइट में इस्तेमाल किया, और बाइनरीसेरियलाइज़र उपलब्ध नहीं होने के कारण डेटाकंट्रेक्टाइज़र का उपयोग किया। जब आप बस ऐसा कर सकते हैं, तो ऑब्जेक्ट क्लोनिंग कोड के पन्नों को लिखने की जरूरत नहीं है। :)
11

3
यह मुझे पंसद है। हालांकि चीजों को "सही" करना अच्छा है, त्वरित और गंदा अक्सर काम में आता है।
ओड्रेड

3
शीघ्र! लेकिन: गंदा क्यों?
raiserle

2
यह गहरा क्लोन और तेज और आसान है। इस पृष्ठ पर अन्य सुझावों पर Carefull। मैंने कई कोशिश की और वे गहरे क्लोन नहीं करते हैं।
RandallTo

2
केवल नकारात्मक पहलू, अगर आप इसे कह सकते हैं, तो यह है कि आपकी कक्षाओं को काम करने के लिए इसे Serializable चिह्नित करना होगा।
तुक्का हापानीमे

29

किसी सूची को क्लोन करने के लिए बस .ToList () को कॉल करें। यह उथली प्रति बनाता है।

Microsoft (R) Roslyn C# Compiler version 2.3.2.62116
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> var x = new List<int>() { 3, 4 };
> var y = x.ToList();
> x.Add(5)
> x
List<int>(3) { 3, 4, 5 }
> y
List<int>(2) { 3, 4 }
> 

3
अब तक का सबसे सरल समाधान
कूर्जोस १४'१

28
थोड़ी चेतावनी यह उथली प्रतिलिपि है ... यह दो सूची ऑब्जेक्ट बनाएगी, लेकिन अंदर की वस्तुएं समान होंगी। यानी एक संपत्ति को बदलने से मूल सूची में एक ही वस्तु / संपत्ति बदल जाएगी।
मार्क जी

22

एक मामूली संशोधन के बाद आप क्लोन भी कर सकते हैं:

public static T DeepClone<T>(T obj)
{
    T objResult;
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, obj);
        ms.Position = 0;
        objResult = (T)bf.Deserialize(ms);
    }
    return objResult;
}

टी को मत भूलो कि धारावाहिक होना चाहिए, अन्यथा आपको System.Runtime.Serialization.SerializationException मिलता है।
बेन्स वेर्टर्ट

अच्छा उत्तर। एक संकेत: आप if (!obj.GetType().IsSerializable) return default(T);पहले बयान के रूप में जोड़ सकते हैं जो अपवाद को रोकता है। और अगर आप इसे एक विस्तार विधि में बदलते हैं, तो आप एल्विस ऑपरेटर का उपयोग भी कर सकते हैं जैसे var b = a?.DeepClone();( var a = new List<string>() { "a", "b" }; उदाहरण के लिए)।
मैट

15

जब तक आपको अपने अंदर की हर एक वस्तु का वास्तविक क्लोन चाहिए, तब तक List<T>सूची को क्लोन करने का सबसे अच्छा तरीका संग्रह सूची के रूप में पुरानी सूची के साथ एक नई सूची बनाना है।

List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);

myListसम्मिलित या हटाने जैसे परिवर्तन प्रभावित नहीं करेंगे cloneOfMyListऔर इसके विपरीत।

हालांकि, दो सूचियों वाली वास्तविक वस्तुएं अभी भी समान हैं।


मैं user49126 से सहमत हूं, मैं देख रहा हूं कि यह एक उथली प्रति है और एक सूची में किए गए परिवर्तन दूसरी सूची में परिलक्षित होते हैं।
सेडलरोनी

1
@ सीडलरोनी, आप गलत हैं। सूची में किए गए परिवर्तन अन्य सूची में शामिल किए गए हैं, सूची में परिवर्तन स्वयं नहीं हैं।
वेलिंगटन ज़ानेली

यह उथली प्रति है।
इलियट चेन

यह एक उथली प्रतिलिपि कैसे है?
एमके

2
@WellingtonZanelli बस ने पुष्टि की है कि myList से एक तत्व को हटाने से इसे क्लोनऑफ मायलिस्ट से भी हटा दिया जाता है।
निक गैलीमोर

13

क्लोन करने के लिए AutoMapper (या जो भी मैपिंग लिबास आप पसंद करते हैं) का उपयोग सरल और बहुत ही कमनीय है।

अपने मानचित्रण को परिभाषित करें:

Mapper.CreateMap<YourType, YourType>();

जादू करो:

YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);

13

यदि आप केवल मूल्य प्रकारों की परवाह करते हैं ...

और आप प्रकार जानते हैं:

List<int> newList = new List<int>(oldList);

यदि आप पहले प्रकार नहीं जानते हैं, तो आपको एक सहायक फ़ंक्शन की आवश्यकता होगी:

List<T> Clone<T>(IEnumerable<T> oldList)
{
    return newList = new List<T>(oldList);
}

तुरंत:

List<string> myNewList = Clone(myOldList);

15
यह तत्वों को क्लोन नहीं करता है।
जेफ येट्स

10

यदि आपने पहले ही Newtonsoft.Json को अपनी परियोजना में संदर्भित किया है और आपकी वस्तुएँ क्रमबद्ध हैं तो आप हमेशा उपयोग कर सकते हैं:

List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))

संभवतः ऐसा करने का सबसे कुशल तरीका नहीं है, लेकिन जब तक आप इसे 100 बार नहीं कर लेते हैं तब तक आप गति अंतर को नोटिस नहीं कर सकते हैं।


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

1
गहरी क्लोनिंग के लिए इस कोड ने मेरे लिए शानदार काम किया। ऐप देव से क्यूए टू प्रॉडक्ट के लिए दस्तावेज़ बॉयलरप्लेट को माइग्रेट कर रहा है। प्रत्येक ऑब्जेक्ट कई दस्तावेज़ टेम्प्लेट ऑब्जेक्ट्स का एक पैकेट है, और बदले में प्रत्येक दस्तावेज़ पैराग्राफ ऑब्जेक्ट्स की एक सूची से मिलकर बनता है। यह कोड मुझे .NET "स्रोत" ऑब्जेक्ट्स को क्रमांकित करने देता है और तुरंत उन्हें नई "लक्ष्य" ऑब्जेक्ट्स के लिए deserialize करता है, जो तब एक अलग वातावरण में SQL डेटाबेस में सहेजे जाते हैं। टन के अनुसंधान के बाद, मुझे बहुत सारी चीजें मिलीं, जिनमें से बहुत अधिक बोझिल थी, और इस कोशिश का फैसला किया। यह छोटा और लचीला दृष्टिकोण "बस सही" था!
डेवलपर

3
public static Object CloneType(Object objtype)
{
    Object lstfinal = new Object();

    using (MemoryStream memStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
        lstfinal = binaryFormatter.Deserialize(memStream);
    }

    return lstfinal;
}

3
public class CloneableList<T> : List<T>, ICloneable where T : ICloneable
{
  public object Clone()
  {
    var clone = new List<T>();
    ForEach(item => clone.Add((T)item.Clone()));
    return clone;
  }
}

3
    public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
    {
        List<TEntity> retList = new List<TEntity>();
        try
        {
            Type sourceType = typeof(TEntity);
            foreach(var o1 in o1List)
            {
                TEntity o2 = new TEntity();
                foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
                {
                    var val = propInfo.GetValue(o1, null);
                    propInfo.SetValue(o2, val);
                }
                retList.Add(o2);
            }
            return retList;
        }
        catch
        {
            return retList;
        }
    }

3

मेरे दोस्त ग्रेगोर मार्टिनोविक और मैं एक जावास्क्रिप्ट सीरियलाइज़र का उपयोग करके इस आसान समाधान के साथ आए। वर्गों को ध्वजांकित करने की आवश्यकता नहीं है और बाइनरीफ़ॉरमैटर का उपयोग करने की तुलना में न्यूटनसॉफ्ट्स जोंसेरीलाइज़र का उपयोग करके हमारे परीक्षणों में भी तेजी लाने की आवश्यकता नहीं है। विस्तार के तरीकों के साथ हर वस्तु पर प्रयोग करने योग्य।

मानक .NET JavascriptSerializer विकल्प:

public static T DeepCopy<T>(this T value)
{
    JavaScriptSerializer js = new JavaScriptSerializer();

    string json = js.Serialize(value);

    return js.Deserialize<T>(json);
}

Newtonsoft JSON का उपयोग करके तेज़ विकल्प :

public static T DeepCopy<T>(this T value)
{
    string json = JsonConvert.SerializeObject(value);

    return JsonConvert.DeserializeObject<T>(json);
}

2
JSON विधि का उपयोग करके निजी सदस्यों को क्लोन नहीं किया जाता है। stackoverflow.com/a/78612/885627
heanshupareek66


3

अगर कोई भी कभी भी इसे पढ़ता है, तो मैं भाग्यशाली रहूंगा ... लेकिन अपने क्लोन तरीकों में किसी प्रकार की ऑब्जेक्ट की सूची वापस न करने के लिए, मैंने एक इंटरफ़ेस बनाया:

public interface IMyCloneable<T>
{
    T Clone();
}

फिर मैंने एक्सटेंशन निर्दिष्ट किया:

public static List<T> Clone<T>(this List<T> listToClone) where T : IMyCloneable<T>
{
    return listToClone.Select(item => (T)item.Clone()).ToList();
}

और यहां मेरे ए / वी मार्किंग सॉफ़्टवेयर में इंटरफ़ेस का कार्यान्वयन है। मैं अपना क्लोन () विधि विडमार्क की एक सूची वापस करना चाहता था (जबकि ICloneable इंटरफ़ेस को वस्तु की सूची वापस करने के लिए मेरी विधि चाहिए थी):

public class VidMark : IMyCloneable<VidMark>
{
    public long Beg { get; set; }
    public long End { get; set; }
    public string Desc { get; set; }
    public int Rank { get; set; } = 0;

    public VidMark Clone()
    {
        return (VidMark)this.MemberwiseClone();
    }
}

और अंत में, एक वर्ग के अंदर विस्तार का उपयोग:

private List<VidMark> _VidMarks;
private List<VidMark> _UndoVidMarks;

//Other methods instantiate and fill the lists

private void SetUndoVidMarks()
{
    _UndoVidMarks = _VidMarks.Clone();
}

किसी को यह पसंद है? कोई सुधार?


2

आप बस सूची का उपयोग करके किसी सरणी में परिवर्तित कर सकते हैं ToArray, और फिर सरणी का उपयोग करके क्लोन कर सकते हैं Array.Clone(...)। आपकी आवश्यकताओं के आधार पर, ऐरे क्लास में शामिल तरीके आपकी आवश्यकताओं को पूरा कर सकते हैं।


यह काम नहीं करता; क्लोन सरणी में मूल्यों में परिवर्तन मूल सूची में मूल्यों को बदल सकते हैं।
बर्नौली छिपकली

आप var clonedList = ListOfStrings.ConvertAll (p => p) का उपयोग कर सकते हैं; जैसा कि @IbrarMumtaz द्वारा दिया गया है .... प्रभावी रूप से काम करता है ... एक सूची में परिवर्तन खुद के लिए रखा जाता है और दूसरे में प्रतिबिंबित नहीं होता है
ज़ैनुल

2

आप एक्सटेंशन विधि का उपयोग कर सकते हैं:

namespace extension
{
    public class ext
    {
        public static List<double> clone(this List<double> t)
        {
            List<double> kop = new List<double>();
            int x;
            for (x = 0; x < t.Count; x++)
            {
                kop.Add(t[x]);
            }
            return kop;
        }
   };

}

आप उदाहरण के लिए उनके मूल्य प्रकार के सदस्यों का उपयोग करके सभी वस्तुओं को क्लोन कर सकते हैं, इस वर्ग पर विचार करें:

public class matrix
{
    public List<List<double>> mat;
    public int rows,cols;
    public matrix clone()
    { 
        // create new object
        matrix copy = new matrix();
        // firstly I can directly copy rows and cols because they are value types
        copy.rows = this.rows;  
        copy.cols = this.cols;
        // but now I can no t directly copy mat because it is not value type so
        int x;
        // I assume I have clone method for List<double>
        for(x=0;x<this.mat.count;x++)
        {
            copy.mat.Add(this.mat[x].clone());
        }
        // then mat is cloned
        return copy; // and copy of original is returned 
    }
};

नोट: यदि आप कॉपी (या क्लोन) पर कोई बदलाव करते हैं तो यह मूल वस्तु को प्रभावित नहीं करेगा।


2

यदि आपको समान क्षमता वाली क्लोन सूची चाहिए, तो आप यह कोशिश कर सकते हैं:

public static List<T> Clone<T>(this List<T> oldList)
{
    var newList = new List<T>(oldList.Capacity);
    newList.AddRange(oldList);
    return newList;
}

1

मैंने अपने स्वयं के कुछ विस्तार के लिए बनाया है, जो उन वस्तुओं के ICollection को परिवर्तित करता है जो IClonable को लागू नहीं करते हैं

static class CollectionExtensions
{
    public static ICollection<T> Clone<T>(this ICollection<T> listToClone)
    {
        var array = new T[listToClone.Count];
        listToClone.CopyTo(array,0);
        return array.ToList();
    }
}

लगता है कि कुछ संग्रह (उदाहरण के लिए सिल्वरलाइट पर
डेटाग्रिड के सिलेक्ट इट्स) कॉपीटॉप

1

मैं ऑब्जेक्ट को कॉपी करने के लिए ऑटोमैपर का उपयोग करता हूं। मैं सिर्फ एक मैपिंग सेटअप करता हूं जो एक ऑब्जेक्ट को अपने आप में मैप करता है। आप इस ऑपरेशन को किसी भी तरह से लपेट सकते हैं।

http://automapper.codeplex.com/


1

इस मामले में, उथले प्रति के लिए, कास्ट का उपयोग करना सहायक हो सकता है:

IList CloneList(IList list)
{
    IList result;
    result = (IList)Activator.CreateInstance(list.GetType());
    foreach (object item in list) result.Add(item);
    return result;
}

सामान्य सूची पर लागू:

List<T> Clone<T>(List<T> argument) => (List<T>)CloneList(argument);

1

एक गहरी प्रतिलिपि के लिए, ICloneable सही समाधान है, लेकिन यहां ICloneable इंटरफ़ेस के बजाय निर्माणकर्ता का उपयोग करते हुए ICloneable के समान दृष्टिकोण है।

public class Student
{
  public Student(Student student)
  {
    FirstName = student.FirstName;
    LastName = student.LastName;
  }

  public string FirstName { get; set; }
  public string LastName { get; set; }
}

// wherever you have the list
List<Student> students;

// and then where you want to make a copy
List<Student> copy = students.Select(s => new Student(s)).ToList();

आपको निम्नलिखित लाइब्रेरी की आवश्यकता होगी जहाँ आप प्रतिलिपि बनाते हैं

using System.Linq

आप System.Linq के बजाय लूप के लिए भी उपयोग कर सकते हैं, लेकिन Linq इसे संक्षिप्त और स्वच्छ बनाता है। इसी तरह आप अन्य सुझावों के अनुसार सुझाव दे सकते हैं और विस्तार के तरीके आदि बना सकते हैं, लेकिन इनमें से कोई भी आवश्यक नहीं है।


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

2
यहां तक ​​कि ICloneable के साथ, आपको अपनी कक्षा पर "क्लोन" विधि करनी होगी। जब तक आप परावर्तन (जिसका उपयोग आप उपर्युक्त दृष्टिकोण में भी कर सकते थे) का उपयोग करते हैं, तब तक क्लोन विधि ऊपर दिए गए कॉपी कंस्ट्रक्टर दृष्टिकोण के समान वास्तविक दिखने वाली है, और नए / परिवर्तित फ़ील्ड्स के अपडेट होने के एक ही मुद्दे से ग्रस्त होगी। लेकिन यह कह रहा है कि "वर्ग के क्षेत्रों में परिवर्तन होने पर वर्ग को अद्यतन करना होगा"। बेशक यह करता है;)
ztorstri 18

0

निम्न कोड को न्यूनतम परिवर्तन के साथ एक सूची में स्थानांतरित करना चाहिए।

मूल रूप से यह प्रत्येक क्रमिक लूप के साथ अधिक से अधिक एक नया यादृच्छिक संख्या सम्मिलित करके काम करता है। यदि पहले से मौजूद संख्याएँ समान या उससे अधिक हैं, तो उन यादृच्छिक संख्याओं को एक में बदल दें ताकि वे यादृच्छिक बड़ी संख्याओं की नई बड़ी श्रेणी में स्थानांतरित हो जाएँ।

// Example Usage
int[] indexes = getRandomUniqueIndexArray(selectFrom.Length, toSet.Length);

for(int i = 0; i < toSet.Length; i++)
    toSet[i] = selectFrom[indexes[i]];


private int[] getRandomUniqueIndexArray(int length, int count)
{
    if(count > length || count < 1 || length < 1)
        return new int[0];

    int[] toReturn = new int[count];
    if(count == length)
    {
        for(int i = 0; i < toReturn.Length; i++) toReturn[i] = i;
        return toReturn;
    }

    Random r = new Random();
    int startPos = count - 1;
    for(int i = startPos; i >= 0; i--)
    {
        int index = r.Next(length - i);
        for(int j = startPos; j > i; j--)
            if(toReturn[j] >= index)
                toReturn[j]++;
        toReturn[i] = index;
    }

    return toReturn;
}

0

एक और बात: आप प्रतिबिंब का उपयोग कर सकते हैं। यदि आप इसे ठीक से कैश करते हैं, तो यह 1,000,000 वस्तुओं को 5.6 सेकंड में (दुख की बात है, आंतरिक वस्तुओं के साथ 16.4 सेकंड) क्लोन करेगा।

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Person
{
       ...
      Job JobDescription
       ...
}

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Job
{...
}

private static readonly Type stringType = typeof (string);

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

    private static readonly MethodInfo CreateCopyReflectionMethod;

    static CopyFactory()
    {
        CreateCopyReflectionMethod = typeof(CopyFactory).GetMethod("CreateCopyReflection", BindingFlags.Static | BindingFlags.Public);
    }

    public static T CreateCopyReflection<T>(T source) where T : new()
    {
        var copyInstance = new T();
        var sourceType = typeof(T);

        PropertyInfo[] propList;
        if (ProperyList.ContainsKey(sourceType))
            propList = ProperyList[sourceType];
        else
        {
            propList = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            ProperyList.Add(sourceType, propList);
        }

        foreach (var prop in propList)
        {
            var value = prop.GetValue(source, null);
            prop.SetValue(copyInstance,
                value != null && prop.PropertyType.IsClass && prop.PropertyType != stringType ? CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { value }) : value, null);
        }

        return copyInstance;
    }

मैंने इसे एक सरल तरीके से मापा, वॉचर क्लास का उपयोग करके।

 var person = new Person
 {
     ...
 };

 for (var i = 0; i < 1000000; i++)
 {
    personList.Add(person);
 }
 var watcher = new Stopwatch();
 watcher.Start();
 var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
 watcher.Stop();
 var elapsed = watcher.Elapsed;

परिणाम: भीतर की वस्तु के साथ व्यक्तित्व - 16.4, व्यक्तिवाद = अशक्त - 5.6

CopyFactory सिर्फ मेरा परीक्षण वर्ग है जहाँ मेरे पास अभिव्यक्ति के उपयोग सहित दर्जनों परीक्षण हैं। आप इसे विस्तार में या जो भी हो, दूसरे रूप में लागू कर सकते हैं। कैशिंग के बारे में मत भूलना।

मैंने अभी तक क्रमिक परीक्षण नहीं किया है, लेकिन मुझे एक लाख कक्षाओं के साथ सुधार में संदेह है। मैं कुछ तेजी से प्रोटोफ्यू / न्यूटन की कोशिश करूँगा।

पुनश्च: सादगी पढ़ने के लिए, मैंने केवल ऑटो-प्रॉपर्टी का इस्तेमाल किया। मैं FieldInfo के साथ अपडेट कर सकता हूं, या आपको इसे आसानी से लागू करना चाहिए।

मैंने हाल ही में बॉक्स से बाहर डीपक्लोन फ़ंक्शन के साथ प्रोटोकॉल बफ़र्स धारावाहिक का परीक्षण किया । यह एक लाख सरल वस्तुओं पर 4.2 सेकंड के साथ जीतता है, लेकिन जब आंतरिक वस्तुओं की बात आती है, तो यह परिणाम 7.4 सेकंड के साथ जीतता है।

Serializer.DeepClone(personList);

सारांश: यदि आपके पास कक्षाओं तक पहुंच नहीं है, तो यह मदद करेगा। अन्यथा यह वस्तुओं की गिनती पर निर्भर करता है। मुझे लगता है कि आप 10,000 वस्तुओं तक प्रतिबिंब का उपयोग कर सकते हैं (शायद थोड़ा कम), लेकिन इससे अधिक के लिए प्रोटोकॉल बफ़र्स धारावाहिक बेहतर प्रदर्शन करेंगे।


0

JSON सीरियलाइज़र और डेज़राइज़र का उपयोग करके C # में ऑब्जेक्ट क्लोन करने का एक सरल तरीका है।

आप एक एक्सटेंशन क्लास बना सकते हैं:

using Newtonsoft.Json;

static class typeExtensions
{
    [Extension()]
    public static T jsonCloneObject<T>(T source)
    {
    string json = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(json);
    }
}

क्लोन और ऑब्जेक्ट के लिए:

obj clonedObj = originalObj.jsonCloneObject;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.