-1

I am facing an annoying issue when I am trying to copy an array. The new array keeps a relation even if it's created by .copy() method. Here is the situation,

Main Class

Dictionary<string, string>[] DataCurrentDict = new Dictionary<string, string>[result.Data.Count()];

// 1. Here the DataCurrentDict array is filled with values, having DataCurrentDict[0]["Weight"] = "0.345";
      
ProductData CurrentProductData = new ProductData(DataCurrentDict);

// 2. Here, the CurrentProductData._ProductDataDict[0]["Weight"] = "0.345", GOOD

DataCurrentDict[0]["Weight"] = "1111";

// 3. Here is the problem... After setting a value into DataCurrentDict, the copied array is modified too! So CurrentProductData._ProductDataDict[0]["Weight"] = "1111" ...Why?

ProductData Class

public class ProductData : IDisposable
{
    private Dictionary<string, string>[] _ProductDataDict;

   //CONSTRUCTOR
   public ProductData(Dictionary<string, string>[] ProductDataDict)
   {
       try
       {
           _ProductDataDict = new Dictionary<string, string>[ProductDataDict.Count()];

           Array.Copy(ProductDataDict, _ProductDataDict, ProductDataDict.Length);
       }
       catch (Exception ex) { }
    }
Filburt
  • 17,626
  • 12
  • 64
  • 115
Jaume
  • 3,672
  • 19
  • 60
  • 119
  • 1
    Its hard to know what you are trying to achieve, but you do know a copy of a reference type aka reference is still the same reference ? – TheGeneral Feb 23 '21 at 23:00
  • @00110001, so how to copy/clone content into a new independent array? I thought that .copy() method was for that instead of an assignment. Thanks – Jaume Feb 23 '21 at 23:05
  • See also https://stackoverflow.com/questions/198496/difference-between-the-system-array-copyto-and-system-array-clone/198500#198500 – Peter Duniho Feb 24 '21 at 00:18

1 Answers1

2

You have an array of reference type, copying the array of reference type gives you the same underlying reference identity, it's as simple as that.

You can think of a reference is an address to something, like a post-it-note to something physical in your cupboard, recreating the post-it-note doesn't move the object.

If you want to recreate the reference identity (allocate new memory for your object), aka your dictionarys, there are several solutions.

_ProductDataDict = ProductDataDict
   .Select(x => x.ToDictionary(y => y.Key, y => y.Value))
   .ToArray();

or (likely more efficient)

_ProductDataDict = ProductDataDict
   .Select(x => new Dictionary<string, string>(x))
   .ToArray();

They both recreate the Dictionary, and both loop through each element and add/hash them to the new dictionary

This is an except of the constructor code of dictionary that takes a dictionary

...
Dictionary<TKey, TValue> d = (Dictionary<TKey, TValue>)dictionary;
int count = d._count;
Entry[]? entries = d._entries;
for (int i = 0; i < count; i++)
{
    if (entries![i].next >= -1)
    {
        Add(entries[i].key, entries[i].value);
    }
}

This is an except from ToDictionary

Dictionary<TKey, TElement> d = new Dictionary<TKey, TElement>(capacity, comparer);
foreach (TSource element in source)
{
    d.Add(keySelector(element), elementSelector(element));
}
halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141