2

I'm trying to create a string with parts and quantities made from data contained in an ICollection. I'm using a List to build the totals I need but when I perform operations on this List it's actually changing the values in the ICollection. I don't want those values changed. Code follows. PartsUsed is the ICollection. Is this because adding individual members of the collection to the list is only pointing to the original data?

private string PartsDetails(out int totalCount, String modtype)
    {

        totalCount = 0;
        var str = new StringBuilder();
        var usedParts = new List<PartUsed>();
        var indexnum = 0;


        foreach (var u in Rma.AssociatedUnits)
        {
            if (u.PartsUsed != null && u.PartsUsed.Count > 0)
            {
                if ((modtype == "ALL"))
                {
                    foreach (var rep in u.PartsUsed)
                    {
                        if (!usedParts.Exists(x => x.Repair.Name == rep.Repair.Name))
                        {
                            usedParts.Add(rep);
                        }
                        else
                        {
                            usedParts[usedParts.FindIndex(f => f.Repair.Name == rep.Repair.Name)].RepairPartQuantity += rep.RepairPartQuantity;
                        }
                    }
                }
            }
        }

        foreach (var partsGroup in usedParts)
        {
            str.AppendFormat(str.Length > 0 ? Environment.NewLine + "{0} - {1}" : "{0} - {1}", partsGroup.RepairPartQuantity, partsGroup.Repair.Name);
            totalCount += partsGroup.RepairPartQuantity;
        }

        return str.ToString();
    }
BigBear2k
  • 19
  • 4

1 Answers1

1

It seems that your PartUsed is a class(e.g. reference type), so u.PartsUsed is actually a collection of references to some objects, so usedParts.Add(rep) is actually adding the same reference(object) to usedParts and when you get and modify one of them in usedParts[usedParts.FindIndex(f => f.Repair.Name == rep.Repair.Name)].RepairPartQuantity += rep.RepairPartQuantity you are actually modifying shared instance. This behavior can be demonstrated like this also:

class MyClass { public int Prop { get; set; }   }

var ref1 = new MyClass{Prop = 1};
var ref2 = ref1;
ref2.Prop = 2;
Console.WriteLine(ref2.Prop);// prints 2

One way around would be to create a clone of PartUsed to put into usedParts but in your particular case it seems that you can use Dictionary<string, int>(assuming RepairPartQuantity is int) for usedParts. Something like this:

var usedParts = new Dictionary<string, int>();

.....
foreach (var rep in u.PartsUsed)
{
      if (!usedParts.ContainsKey(rep.Repair.Name))
      {
          usedParts[rep.Repair.Name] = rep.RepairPartQuantity;
      }
      else
      {
          usedParts[rep.Repair.Name] += rep.RepairPartQuantity;
      }
}

foreach (var kvp in usedParts)
    {
        str.AppendFormat(str.Length > 0 ? Environment.NewLine + "{0} - {1}" : "{0} - {1}", kvp.Value, kvp.Key);
        totalCount += kvp.Value;
    }
Guru Stron
  • 102,774
  • 10
  • 95
  • 132