.NET জেনেরিক অভিধান <স্ট্রিং, টি> ক্লোন / গভীর অনুলিপি করার সর্বোত্তম উপায় কী?


211

আমি একটি জেনেরিক অভিধান পেয়েছি Dictionary<string, T>যা আমি অবশ্যই কোনও ক্লোন () তৈরি করতে চাই)

উত্তর:


184

ঠিক আছে, .NET 2.0 উত্তর:

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

আপনি যদি না মান ক্লোন করতে, আপনি ভালো কিছু ব্যবহার করতে পারেন:

public static Dictionary<TKey, TValue> CloneDictionaryCloningValues<TKey, TValue>
   (Dictionary<TKey, TValue> original) where TValue : ICloneable
{
    Dictionary<TKey, TValue> ret = new Dictionary<TKey, TValue>(original.Count,
                                                            original.Comparer);
    foreach (KeyValuePair<TKey, TValue> entry in original)
    {
        ret.Add(entry.Key, (TValue) entry.Value.Clone());
    }
    return ret;
}

এটি TValue.Clone()অবশ্যই যথেষ্ট গভীর ক্লোন হওয়ার উপর নির্ভর করে ।


যদিও আমি মনে করি এটি কেবল অভিধান মানগুলির অগভীর অনুলিপি করছে। entry.Valueমান হতে পারে আরেকটি [সাব] সংগ্রহ।
ক্রিসডাব্লু

6
@ ক্রিসডাব্লু: আচ্ছা এটি প্রতিটি মানকে ক্লোন করতে বলেছে - এটি Clone()গভীর বা অগভীর কিনা তা পদ্ধতি অনুসারে। আমি সেই প্রভাবটিতে একটি নোট যুক্ত করেছি।
জন স্কিটি

1
@ সাইদগঞ্জি: ঠিক আছে যদি মানগুলি ক্লোন করার প্রয়োজন না হয় তবে "অভিধানটিতে নির্মাণকারীর ওভারলোড ব্যবহার করুন যা একটি বিদ্যমান আইডিয়েরিয়া লাগে" ঠিক আছে, এবং ইতিমধ্যে আমার উত্তরে রয়েছে। মান যদি না ক্লোন করা প্রয়োজন, তাহলে উত্তরটি আপনাকে সাথে সংযুক্ত আছেন তাহলে না সাহায্যের এ সব আছে।
জন স্কিটি

1
@ সাইদগঞ্জি: হ্যাঁ, এটা ঠিক হওয়া উচিত। (অবশ্যই, যদি স্ট্রাক্টগুলিতে পরিবর্তনীয় রেফারেন্সের ধরণের রেফারেন্স থাকে তবে এটি এখনও সমস্যা হতে পারে ... তবে আশাকরি সমস্যাটি এমন নয় not)
জোন স্কিট

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

210

(দ্রষ্টব্য: যদিও ক্লোনিং সংস্করণটি সম্ভাব্যভাবে কার্যকর, তবে একটি সাধারণ অগভীর অনুলিপিটির জন্য আমি অন্য পোস্টে যে কনস্ট্রাক্টরটি উল্লেখ করেছি এটি একটি ভাল বিকল্প)

আপনি অনুলিপিটি কতটা গভীর হতে চান এবং আপনি নেট নেট এর কোন সংস্করণ ব্যবহার করছেন? আমি সন্দেহ করি যে টিনডোরের কাছে একটি লিনকিউ কল, কী এবং উপাদান নির্বাচক উভয়ই নির্দিষ্ট করে, আপনি যদি নেট .৩.৫ ব্যবহার করেন তবে যাওয়ার সবচেয়ে সহজ উপায় হবে।

উদাহরণস্বরূপ, যদি আপনি মানটিকে অগভীর ক্লোন হিসাবে মানা না করেন:

var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
                                               entry => entry.Value);

আপনি যদি ইতিমধ্যে ICloneable বাস্তবায়ন করতে টি সীমাবদ্ধ করে থাকেন:

var newDictionary = oldDictionary.ToDictionary(entry => entry.Key, 
                                               entry => (T) entry.Value.Clone());

(এগুলি অনির্ধারিত, তবে কাজ করা উচিত))


জনের উত্তরের জন্য ধন্যবাদ। আমি প্রকৃতপক্ষে ফ্রেমওয়ার্কটির v2.0 ব্যবহার করছি।
মাইকিমো

এই প্রসঙ্গে "এন্ট্রি => এন্ট্রি.কি, এন্ট্রি => এন্ট্রি.ভ্যালু" কী। কীভাবে আমি কী এবং মান যুক্ত করব। এটি আমার শেষে একটি ত্রুটি দেখাচ্ছে
প্রতীক

2
@ প্রতীক: এগুলি ল্যাম্বডা এক্সপ্রেশন - সি # ৩ এর অংশ
জন স্কিটি

2
ডিফল্টরূপে লিনকুইয়ের টোডে অভিধানে তুলকটি অনুলিপি করে না। আপনি আপনার অন্যান্য উত্তরে তুলনামূলক অনুলিপি করার কথা উল্লেখ করেছেন, তবে আমি ভাবছি ক্লোনিংয়ের এই সংস্করণটিও তুলনাকারীকে পাস করা উচিত।
ব্যবহারকারী420667

86
Dictionary<string, int> dictionary = new Dictionary<string, int>();

Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);

5
মানগুলির পয়েন্টারগুলি এখনও একই, আপনি যদি অনুলিপিতে মানগুলিতে পরিবর্তনগুলি প্রয়োগ করেন, পরিবর্তনগুলি অভিধান অবজেক্টেও প্রতিফলিত হবে।
ফোক্কো ড্রাইজপ্রং

3
@ ফোকোড্রাইজ এটি কোনভাবেই প্রাসঙ্গিক নয়, এটি কেবল নতুন বস্তুতে কী

17
এটি অবশ্যই কার্যকরভাবে কাজ করে - এটি কী এবং মান উভয়ের ক্লোন তৈরি করে। অবশ্যই, এটি কেবল তখনই কাজ করে যদি মানটি কোনও রেফারেন্স টাইপ না হয়, যদি মানটি কোনও রেফারেন্স টাইপ হয় তবে কার্যকরভাবে কেবল কীগুলির অনুলিপি হিসাবে এটি একটি অগভীর অনুলিপি হিসাবে নেয়।
কনটাঙ্গো

1
@ কনটাঙ্গো তাই এই ক্ষেত্রে স্ট্রিং এবং ইন্টি রেফারেন্স টাইপ না হওয়ায় এটি ঠিক কাজ করবে?
মনস্টার এমএমআরপিজি

3
@ উউরআল্ডানমাজ আপনি কোনও রেফারেন্স করা অবজেক্টের প্রকৃত পরিবর্তন পরীক্ষা করতে ভুলে গেছেন, আপনি ক্লোনীকৃত অভিধানগুলিতে কেবলমাত্র মান পয়েন্টার প্রতিস্থাপনের পরীক্ষা করেন যা স্পষ্টতই কাজ করে, তবে আপনি যদি পরীক্ষার অবজেক্টগুলিতে বৈশিষ্ট্যগুলি পরিবর্তন করেন তবে আপনার পরীক্ষাগুলি ব্যর্থ হবে: ডটনেটফিটালটনেট / xmPPKr
জেনস

10

.NET 2.0 এর জন্য আপনি কোনও শ্রেণি প্রয়োগ করতে পারেন যা উত্তরাধিকার সূত্রে প্রাপ্ত Dictionaryএবং প্রয়োগ করে ICloneable

public class CloneableDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TValue : ICloneable
{
    public IDictionary<TKey, TValue> Clone()
    {
        CloneableDictionary<TKey, TValue> clone = new CloneableDictionary<TKey, TValue>();

        foreach (KeyValuePair<TKey, TValue> pair in this)
        {
            clone.Add(pair.Key, (TValue)pair.Value.Clone());
        }

        return clone;
    }
}

এরপরে আপনি Cloneপদ্ধতিটি কল করে অভিধানটি ক্লোন করতে পারেন । অবশ্যই এই বাস্তবায়নের জন্য অভিধানের মান ধরণের প্রয়োগের প্রয়োজনীয়তা রয়েছে ICloneableতবে অন্যথায় জেনেরিক বাস্তবায়ন মোটেই ব্যবহারিক নয়।


8

এটি আমার পক্ষে ভাল কাজ করে

 // assuming this fills the List
 List<Dictionary<string, string>> obj = this.getData(); 

 List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);

টোমর ওলবার্গ মন্তব্যগুলিতে যেমন বর্ণনা করেছেন, মানের ধরণটি পরিবর্তনীয় শ্রেণীর হলে এটি কাজ করে না।


1
এটি গুরুত্ব সহকারে upvotes প্রয়োজন! মূল অভিধানটি যদি কেবল পঠনযোগ্য হয় তবে এটি এখনও কাজ করবে: var newDict = readonlyDict.ToD शब्दकोয় (কেভিপি => কেভিপি.কি, কেভিপি => কেভিপি.ভ্যালু)
স্টিফান রায়ার

2
মানের
ধরণটি

5

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

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

object deepcopy = FromBinary(ToBinary(yourDictionary));

public Byte[] ToBinary()
{
  MemoryStream ms = null;
  Byte[] byteArray = null;
  try
  {
    BinaryFormatter serializer = new BinaryFormatter();
    ms = new MemoryStream();
    serializer.Serialize(ms, this);
    byteArray = ms.ToArray();
  }
  catch (Exception unexpected)
  {
    Trace.Fail(unexpected.Message);
    throw;
  }
  finally
  {
    if (ms != null)
      ms.Close();
  }
  return byteArray;
}

public object FromBinary(Byte[] buffer)
{
  MemoryStream ms = null;
  object deserializedObject = null;

  try
  {
    BinaryFormatter serializer = new BinaryFormatter();
    ms = new MemoryStream();
    ms.Write(buffer, 0, buffer.Length);
    ms.Position = 0;
    deserializedObject = serializer.Deserialize(ms);
  }
  finally
  {
    if (ms != null)
      ms.Close();
  }
  return deserializedObject;
}

5

আমার পক্ষে সবচেয়ে ভাল উপায় হ'ল:

Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);

3
অভিধানটি একটি রেফারেন্স টাইপ হওয়ায় এটি কেবল রেফারেন্সটি অনুলিপি করছে না? এর অর্থ আপনি যদি একটিতে মান পরিবর্তন করেন তবে এটি অন্যটিতে মান পরিবর্তন করবে?
গোকু

3

বাইনারি সিরিয়ালাইজেশন পদ্ধতিটি দুর্দান্ত কাজ করে তবে আমার পরীক্ষাগুলিতে এটি ক্লোনটির অ-সিরিয়ালাইজেশন প্রয়োগের চেয়ে 10x ধীর হয়ে গেছে। এটি পরীক্ষিতDictionary<string , List<double>>


আপনি কি নিশ্চিত যে আপনি একটি গভীর গভীর অনুলিপি করেছেন? দুটি স্ট্রিং এবং লিস্টের গভীর কপি করা দরকার। এছাড়া এটি ধীর হতে ঘটাচ্ছে ধারাবাহিকতাতে সংস্করণে কিছু বাগ আছে: মধ্যে পদ্ধতি সঙ্গে বলা হয় পরিবর্তে । তারপরে বাইটে [] প্রথমে ম্যান স্ট্রিমে ম্যানুয়ালি অনুলিপি করা হয় তবে এটি কেবল এটির নির্মাণকারীকে সরবরাহ করা যেতে পারে। ToBinary()Serialize()thisyourDictionaryFromBinary()
বৃহস্পতি

1

আমি যখন একটি অভিধান <স্ট্রিং, স্ট্রিং> গভীরভাবে অনুলিপি করার চেষ্টা করছিলাম তখন এটিই আমাকে সাহায্য করেছিল

Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);

শুভকামনা


নেট 4.6.1 এর জন্য ভাল কাজ করে। এটি আপডেট হওয়া উত্তর হওয়া উচিত।
তাল্লাল কাজমী

0

কী / মানগুলি আইকনলোনযোগ্য হয় তবে এটি চেষ্টা করুন:

    public static Dictionary<K,V> CloneDictionary<K,V>(Dictionary<K,V> dict) where K : ICloneable where V : ICloneable
    {
        Dictionary<K, V> newDict = null;

        if (dict != null)
        {
            // If the key and value are value types, just use copy constructor.
            if (((typeof(K).IsValueType || typeof(K) == typeof(string)) &&
                 (typeof(V).IsValueType) || typeof(V) == typeof(string)))
            {
                newDict = new Dictionary<K, V>(dict);
            }
            else // prepare to clone key or value or both
            {
                newDict = new Dictionary<K, V>();

                foreach (KeyValuePair<K, V> kvp in dict)
                {
                    K key;
                    if (typeof(K).IsValueType || typeof(K) == typeof(string))
                    {
                        key = kvp.Key;
                    }
                    else
                    {
                        key = (K)kvp.Key.Clone();
                    }
                    V value;
                    if (typeof(V).IsValueType || typeof(V) == typeof(string))
                    {
                        value = kvp.Value;
                    }
                    else
                    {
                        value = (V)kvp.Value.Clone();
                    }

                    newDict[key] = value;
                }
            }
        }

        return newDict;
    }

0

পুরানো পোস্টে উত্তর দিলেও আমি এটি নীচে মোড়ানো দরকারী বলে মনে করি:

using System;
using System.Collections.Generic;

public class DeepCopy
{
  public static Dictionary<T1, T2> CloneKeys<T1, T2>(Dictionary<T1, T2> dict)
    where T1 : ICloneable
  {
    if (dict == null)
      return null;
    Dictionary<T1, T2> ret = new Dictionary<T1, T2>();
    foreach (var e in dict)
      ret[(T1)e.Key.Clone()] = e.Value;
    return ret;
  }

  public static Dictionary<T1, T2> CloneValues<T1, T2>(Dictionary<T1, T2> dict)
    where T2 : ICloneable
  {
    if (dict == null)
      return null;
    Dictionary<T1, T2> ret = new Dictionary<T1, T2>();
    foreach (var e in dict)
      ret[e.Key] = (T2)(e.Value.Clone());
    return ret;
  }

  public static Dictionary<T1, T2> Clone<T1, T2>(Dictionary<T1, T2> dict)
    where T1 : ICloneable
    where T2 : ICloneable
  {
    if (dict == null)
      return null;
    Dictionary<T1, T2> ret = new Dictionary<T1, T2>();
    foreach (var e in dict)
      ret[(T1)e.Key.Clone()] = (T2)(e.Value.Clone());
    return ret;
  }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.