Ho un dizionario generico Dizionario che vorrei essenzialmente fare un Clone() di ... tutti i suggerimenti.Qual è il modo migliore per clonare/copiare in profondità un dizionario generico .NET <string, T>?
Qual è il modo migliore per clonare/copiare in profondità un dizionario generico .NET <string, T>?
risposta
Va bene, le risposte di .NET 2.0:.
Se non è necessario cl uno dei valori, è possibile utilizzare il sovraccarico del costruttore nel Dizionario che accetta un IDictionary esistente. (È possibile specificare l'operatore di confronto come di confronto del dizionario esistente, anche.)
Se fai necessità di clonare i valori, è possibile utilizzare qualcosa di simile:
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;
}
che si basa su TValue.Clone()
essere un clone opportunamente profondo, naturalmente.
(Nota: anche se la versione clonazione è potenzialmente utile, per una semplice copia superficiale costruttore ho citato in un altro post è una scelta migliore.)
Come profondo cosa vuoi la copia di essere, e quali versione di .NET stai usando? Sospetto che una chiamata LINQ a ToDictionary, che specifica sia la chiave che il selettore di elementi, sarà il modo più semplice per andare se si utilizza .NET 3.5.
Per esempio, se non ti dispiace il valore di essere un clone superficiale:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Se hai già costretti T per implementare ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Quelle sono testati, ma dovrebbe funzionare)
Per .NET 2.0 è possibile implementare una classe che eredita da Dictionary
e implementa 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;
}
}
È quindi possibile clonare il dizionario semplicemente chiamando il metodo Clone
. Ovviamente questa implementazione richiede che il tipo di valore del dizionario implementi ICloneable
, ma in caso contrario un'implementazione generica non è affatto pratica.
È sempre possibile utilizzare la serializzazione. Potresti serializzare l'oggetto e poi deserializzarlo. Ciò ti darà una copia profonda del dizionario e di tutti gli elementi al suo interno. Ora puoi creare una copia profonda di qualsiasi oggetto contrassegnato come [Serializable] senza scrivere alcun codice speciale.
Ecco due metodi che utilizzeranno la serializzazione binaria. Se si utilizzano questi metodi è sufficiente chiamare
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;
}
metodo serializzazione binaria funziona bene, ma nel mio test ha dimostrato di essere 10 volte più lento di un'implementazione non serializzazione del clone.Testato su Dictionary<string , List<double>>
Sei sicuro di aver fatto una copia completa? Sia le stringhe che gli elenchi devono essere copiati in profondità. Ci sono anche alcuni bug nella versione di serializzazione che lo rendono lento: in 'ToBinary()' il metodo 'Serialize()' viene chiamato con 'this' invece di' yourDictionary'. Quindi in 'FromBinary()' il byte [] viene prima copiato manualmente su MemStream ma può essere solo fornito al suo costruttore. – Jupiter
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
I puntatori dei valori sono sempre gli stessi, se applicate le modifiche ai valori in copia, le modifiche si rifletteranno anche sull'oggetto dizionario. –
@FokkoDriesprong no, non fa altro, copia semplicemente keyValuePairs nel nuovo oggetto –
Ciò sicuramente funziona bene - crea un clone sia della chiave che del valore. Naturalmente, questo funziona solo se il valore NON è un tipo di riferimento, se il valore è un tipo di riferimento, quindi in realtà utilizza solo una copia dei tasti come copia superficiale. – Contango
Il modo migliore per me è questa:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
Herald Smit ha scritto già su questo modo. – RredCat
Prova questa se chiave/valori sono ICloneable:
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;
}
Rispondendo sul vecchio post Tuttavia ho trovato che utile per avvolgerlo come segue:
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;
}
}
- 1. Qual è il modo migliore per impostare tutti i valori in un dizionario C# <string,bool>?
- 2. Qual è il modo migliore per convertire String in ByteString
- 3. Qual è il modo migliore per tagliare() tutti gli elementi in un elenco <String>?
- 4. Qual è il modo migliore per ordinare un IList <T> in .Net 2.0?
- 5. Qual è il modo migliore per copiare in profondità un hash di hash in Perl?
- 6. Il modo migliore per filtrare un dizionario in Python
- 7. Il modo migliore per interrogare un dizionario in C#
- 8. Qual è il modo migliore per supportare più database per un prodotto .NET?
- 9. LINQ query per restituire un dizionario <string, string>
- 10. pitone: qual è il modo migliore per controllare più chiavi esiste in un dizionario?
- 11. Qual è il modo migliore per convertire una stringa separata da caratteri di ritorno in un elenco <string>?
- 12. Qual è il modo migliore per combinare un percorso e un nome file in C# /. NET?
- 13. Un dizionario annidato in profondità è un antipattern?
- 14. Qual è il modo migliore per eseguire un'espressione matematica?
- 15. Qual è il modo migliore per inviare un repository generico tramite WCF?
- 16. Perché è un dizionario generico .net così grande
- 17. Qual è il modo migliore per gestire un albero delle dipendenze in .NET?
- 18. Qual è il modo migliore per serializzare jSON un DataTable .NET in WCF?
- 19. Qual è il modo migliore per convertire enum in stringa?
- 20. Convertire il dizionario <String,Int> nel dizionario <String, SomeEnum> utilizzando LINQ?
- 21. Qual è il modo migliore per aggiungere un articolo a un oggetto IEnumerable <T>?
- 22. Qual è il modo migliore per costruire un NSCompoundPredicate complesso?
- 23. modo migliore per ordinare un dizionario in gruppi utilizzando Python
- 24. Qual è il modo migliore per chiudere un ramo Mercurial?
- 25. Qual è il modo migliore per convertire XMLGregorianCalendar in MM/gg/aaaa hh: mm String?
- 26. Qual è il modo migliore per ridimensionare un oggetto BitmapData?
- 27. Qual è il modo migliore per attuare questo GetHashCode composito()
- 28. modo generico per uscire da un'applicazione .NET
- 29. Dizionario cast di C# <string, AnyType> al dizionario <string, Object> (Coinvolgimento del riflesso)
- 30. .NET - Qual è il modo migliore per implementare un gestore di catch all exception "
Penso che stia facendo solo una copia superficiale dei valori del dizionario, comunque. Il valore 'entry.Value' potrebbe essere ancora un altro [sotto] insieme. – ChrisW
@ChrisW: Beh, questo è chiedere a ciascun valore di essere clonato: dipende dal metodo 'Clone()' che sia profondo o poco profondo. Ho aggiunto una nota in tal senso. –