41

I know that we should rather be using dictionaries as opposed to hashtables. I cannot find a way to clone the dictionary though. Even if casting it to ICollection which I do to get the SyncRoot, which I know is also frowned upon.

I am busy changing that now. Am I under the correct assumption that there is no way to implement any sort of cloning in a generic way which is why clone is not supported for dictionary?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
uriDium
  • 13,110
  • 20
  • 78
  • 138
  • 3
    Look at http://stackoverflow.com/questions/139592/what-is-the-best-way-to-clone-deep-copy-a-net-generic-dictionarystring-t – sashaeve Feb 17 '10 at 09:53
  • I saw that but I don't care about deep copy. A clone shallow copy will do. Also there is a second part to my question which is: Is the reason that there is no clone because of the difficulty that generics introduces? – uriDium Feb 17 '10 at 12:55

7 Answers7

60

Use the Constructor that takes a Dictionary. See this example

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

dict.Add("SO", "StackOverflow");

var secondDict = new Dictionary<string, string>(dict);

dict = null;

Console.WriteLine(secondDict["SO"]);

And just for fun.. You can use LINQ! Which is a bit more Generic approach.

var secondDict = (from x in dict
                  select x).ToDictionary(x => x.Key, x => x.Value);

Edit

This should work well with Reference Types, I tried the following:

internal class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public User Parent { get; set; }
}

And the modified code from above

var dict = new Dictionary<string, User>();

dict.Add("First", new User 
    { Id = 1, Name = "Filip Ekberg", Parent = null });

dict.Add("Second", new User 
    { Id = 2, Name = "Test test", Parent = dict["First"] });

var secondDict = (from x in dict
                  select x).ToDictionary(x => x.Key, x => x.Value);

dict.Clear();

dict = null;

Console.WriteLine(secondDict["First"].Name);

Which outputs "Filip Ekberg".

Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Filip Ekberg
  • 36,033
  • 20
  • 126
  • 183
  • 9
    Just keep in mind that the first approach will create a shallow copy, i.e. the objects are not copied as well. For strings that is not really an issue but for other reference types it may be. – Brian Rasmussen Feb 17 '10 at 10:05
  • With the LINQ-expression it should at least copy the references. And when the GC find dict and it's null, but the references are not, they shoulndn't be removed, am i right? So it _should_ work on reference types aswell. – Filip Ekberg Feb 17 '10 at 10:09
  • 3
    Worth to note: This approach will not clone the `IEqualityComparer` of the source `IDictionary`, i.e. if you have an `IDictionary` with a `StringComparer.OrdinalIgnoreCase`. – Dennis Aug 01 '13 at 10:00
  • The first example also should not say "dict = null;" but "dict.clear();" to really prove that the new one is not just a reference. – Andreas Reiff Oct 22 '15 at 14:32
  • 4
    Your reference example is misleading/incorrect -- the referenced type is still the same instance in both collections: https://dotnetfiddle.net/AMRtta -- change `dict["First"].Name` and it'll also be changed in `secondDict["First"].Name`. Removing it from one collection isn't the same thing as modifying it. Also, if you're gonna use Linq: just `dict.ToDictionary` rather than `(from x in dict select x).ToDictionary`. – drzaus May 25 '16 at 16:14
2

This is a quick and dirty clone method I once wrote...the initial idea is from CodeProject, I think.

Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

Public Shared Function Clone(Of T)(ByVal inputObj As T) As T
    'creating a Memorystream which works like a temporary storeage '
    Using memStrm As New MemoryStream()
        'Binary Formatter for serializing the object into memory stream '
        Dim binFormatter As New BinaryFormatter(Nothing, New StreamingContext(StreamingContextStates.Clone))

        'talks for itself '
        binFormatter.Serialize(memStrm, inputObj)

        'setting the memorystream to the start of it '
        memStrm.Seek(0, SeekOrigin.Begin)

        'try to cast the serialized item into our Item '
        Try
            return DirectCast(binFormatter.Deserialize(memStrm), T)
        Catch ex As Exception
            Trace.TraceError(ex.Message)
            return Nothing
        End Try
    End Using
End Function

Useage:

Dim clonedDict As Dictionary(Of String, String) = Clone(Of Dictionary(Of String, String))(yourOriginalDict)
Bobby
  • 11,419
  • 5
  • 44
  • 69
2

Just in cause anyone needs the vb.net version

Dim dictionaryCloned As Dictionary(Of String, String)
dictionaryCloned  = (From x In originalDictionary Select x).ToDictionary(Function(p) p.Key, Function(p) p.Value)
Amarnasan
  • 14,939
  • 5
  • 33
  • 37
1

For Vb.net I discovered a more simple solution:

dim seconddic as Dictionary(of string,string) = new Dictionary(of string,string)(originaldic)
mono código
  • 405
  • 1
  • 6
  • 10
Ukkie
  • 15
  • 7
0

For a primitive type dictionary

Public Sub runIntDictionary()
  Dim myIntegerDict As New Dictionary(Of Integer, Integer) From {{0, 0}, {1, 1}, {2, 2}}
  Dim cloneIntegerDict As New Dictionary(Of Integer, Integer)
  cloneIntegerDict = myIntegerDict.Select(Function(x) x.Key).ToList().ToDictionary(Of Integer, Integer)(Function(x) x, Function(y) myIntegerDict(y))
End Sub

For a dictionary of an Object that implements ICloneable

Public Sub runObjectDictionary()
  Dim myDict As New Dictionary(Of Integer, number) From {{3, New number(3)}, {4, New number(4)}, {5, New number(5)}}
  Dim cloneDict As New Dictionary(Of Integer, number)
  cloneDict = myDict.Select(Function(x) x.Key).ToList().ToDictionary(Of Integer, number)(Function(x) x, Function(y) myDict(y).Clone)
End Sub

Public Class number
  Implements ICloneable
  Sub New()
  End Sub
  Sub New(ByVal newNumber As Integer)
    nr = newnumber
  End Sub
  Public nr As Integer

  Public Function Clone() As Object Implements ICloneable.Clone
    Return New number With {.nr = nr}
  End Function
  Public Overrides Function ToString() As String
    Return nr.ToString
  End Function
End Class
Marcello
  • 438
  • 5
  • 21
0

For simple Dictionary<String, Object>

public static Dictionary<string, object> DictionaryClone(Dictionary<string, object> _Datas)
{
    Dictionary<string, object> output = new Dictionary<string, object>();

    if (_Datas != null)
    {
        foreach (var item in _Datas)
            output.Add(item.Key, item.Value);
    }

    return output;
}
0

Simplest way:

Dictionary<string, int> oldDictionary = new Dictionary<string, int>();

Dictionary<string, int> newDictionary = new Dictionary<string, int>(oldDictionary);
Dmitry Shashurov
  • 1,148
  • 13
  • 11