0

In .NET WinForms C# app, I have a Dictionary<string, RefItemDetails> collection named listItems. I store data in it on start of the app. In a static class I have as follows:

    // listItems is populated bt reading a file. 
    // No other operations are performed on it, except finding an item.
    public static Dictionary<string, RefItemDetails> itemsList;
    
   // Find RefItemDetails of barcode
    public static RefItemDetails FindRefItem(string barcode)
    {
        RefItemDetails itemDet = null;
        try
        {
            //if (itemsList.TryGetValue(barcode, out itemDet) == false)
            //    System.Diagnostics.Debug.WriteLine("Barcode " + barcode + " not found in Items");
            
            //itemDet = itemsList.First(item => item.Key == barcode);//.First(item => item.Barcode == barcode);

            if (itemsList.ContainsKey(barcode)) 
                itemDet = itemsList[barcode];
        }
        catch (Exception)
        {
            itemDet = null;
        }

        return itemDet;
    }

For retrieving an item from listItems in another class, I use :

    refScannedItem = null;
    // Get Unit Barcode & Search RefItem of it
    refScannedItem = UtilityLibrary.FindRefItem(boxItem.UnitBarcode.Trim());

     // Display BOX item details 
     refScannedItem.Barcode = boxItem.BoxBarcode.Trim();
     refScannedItem.Description = "BOX of " + boxItem.Quantity + " " + refScannedItem.Description;
     refScannedItem.Retail *= boxItem.Quantity;
     refScannedItem.CurrentCost *= boxItem.Quantity;

Here what happens above is, I search for an item & I get it "refScannedItem" and I append the Description of it by "BOX of " + boxItem.Quantity + " " + refScannedItem.Description; . So if the original Description was "Aquafina", I make it "BOXof 10 Aquafina". The nest time I scan the same product, I find the product, but now its descrption has become "Box of 10 Aquafina", so my line of setting Description turns to "BOX of 10 BOX of 10 Aquafina". The same goes on like "BOX of 10 BOX of 10 BOX of 10 Aquafina" and so on.

As you cna see in my find code, I had initially used TryGetValue, then tried using LINQ, then tried using ContainsKey, but in all of them why does the value of listItem get updated.

I understand that as TryGetValue has out parameter, so the value is passed as a reference, and then it will be chnaged. But in listItems[key] also updates it !!! How can I avoid this to happen ? I had selected Dictionary collection for easy & fast searching, but this part gives a lot of problems and a big bug too on my app. I couldn't find nay solution where the receive the value but shouldn't be updated. All articles shows how to search & update it.

Kindly suggest a solution for the above. Any help is highly appreciated.

Thanks

Vizel Leonid
  • 456
  • 7
  • 15
Tvd
  • 4,463
  • 18
  • 79
  • 125

5 Answers5

1

You return a pointer to the item contained in your Dictionary, so it makes sense that any manipulations you make to this Object will be stored in the original Dictionary object.

What you want to do is, in FindRefItem, return a pointer to a copy of your RefItemDetails object.

An easy way to do this would be to write a new constructor. Something like:

public RefItemDetails(RefItemDetails original)
{
   this.Barcode = original.Barcode ;
   this.Description = original.Description ;
   this.Retail = original.Retail ;
   this.CurrentCost = original.CurrentCost ;
   //Set any other properties here
}

and then replace return itemDet; with return new RefItemDetails(itemDet);

Nils O
  • 1,321
  • 9
  • 19
  • Thanks @Nils O, this did the trick. I was thinking to send the item in some other way only rather than itemDet. But was also wondering, why Dictionary updates the value object in any way. As per you said, I got it that Dictionary sends pointer refernce only, s obviously it will be updated only. Once again, Thanks. – Tvd Apr 21 '15 at 13:52
1

I think you are going about this the wrong way.

You shouldn't have a writeable Description property that you update whenever the quantity changes.

Instead, I think you should have a separate Name property which contains the name of the item (e.g. Aquafina) and a dynamically-created readonly Description property like so:

public string Description
{
    get
    {
        return string.Format("Box of {0} {1}", Quantity, Name);
    }
}

Or something along similar lines.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • then he next time I use Name and/or Description, will face the same issue. So that wont work with my case. Thanks for your response. – Tvd Apr 21 '15 at 13:53
0

This should do the trick:

if (!refScannedItem.Description.StartsWith("BOX of "))
{
    refScannedItem.Description = "BOX of " + boxItem.Quantity + " " + refScannedItem.Description;
}
GregoryHouseMD
  • 2,168
  • 1
  • 21
  • 37
  • That will find it but won't account for the other modifications he is making afterwards. – Sign Apr 21 '15 at 13:00
  • @GregoryHouseMD, this was already in my mind, the for the same item may not need the text "BOX of " only. So the Description in the Dictionary shouldn't be changed is my point. – Tvd Apr 21 '15 at 13:20
0

You are getting an object from a Dictionary - and then changing it, so of course it's properties will change in the Dictionary as well ... you haven't cloned it so why would you be taking a copy?

The solution is quite simply not to change the values of the item and use the amended text in a different way:

var amendedDescription = "BOX of " + boxItem.Quantity + " " + refScannedItem.Description;
James Harcourt
  • 6,017
  • 4
  • 22
  • 42
  • No @James, I use refScannedItem object in other parts of the application where I assign it's value to other controls. Hence this can't be appropriate for me. Thanks. – Tvd Apr 21 '15 at 13:55
0

Looks like you need to make a copy of the RefItemDetails to make modifications to after you get it back from the call to UtilityLibrary.FindRefItem(boxItem.UnitBarcode.Trim())

Sign
  • 1,919
  • 18
  • 33