0

I created a list based on struct but can't change item value. so I used a class instead of struct but the problem when I printed the list it's give me the latest item inserted duplicate as per the number of items.

eg. if I insert "A" , "B" , "C" then output will be C C C not A B C

Here is the code :

public struct Item     //this is working fine but can't change item price
{
    public string Code { get; set; }
    public string Description{ get; set; }
    public string Price{ get; set; }
    public string Qty { get; set; }
}

public static Class Item   //this is not working it's overwrite the last value
{
    public string Code { get; set; }
    public string Description{ get; set; }
    public string Price{ get; set; }
    public string Qty { get; set; }
}

Rest of code

public static Item xItem = new Item();
public static List<Item> item = new List<Item>();

xItem.Code = txtCode.Text;
xItem.Description = txtDescription.text;
xItem.Price= txtPrice.text;
xItem.Qty = txtQty.text;

I tried both of this (gives same result)

item.Insert(i,xItem);
// and
item.Add(xItem);

in btnSave_Click I add this

foreach (var s in item)
{
  System.Diagnostics.Debug.WriteLine(s.Code +" \t " + s.Qty);
}
  • sorry for that, now updated. – Mohammad Sufian Al-Omar Jul 24 '18 at 13:38
  • 3
    You should have a look upon reference-types (=classes) and value-types (=structs). Reference-types are - as the name implies - references to the exact same instance, whereas on value-types you copy the instance everytime you pass it to a method. – MakePeaceGreatAgain Jul 24 '18 at 13:39
  • You should probably not use `struct` unless you have read up on it, stick to `class` until now. – Micha Wiedenmann Jul 24 '18 at 13:39
  • How many times do you have `new Item()` in your class based code? That's how many *actual instances of `Item`* that you've created. You may have multiple reference to a single instance, and I suspect the answer to my question is 1 - so you'll have, say, 3 references stored in your list but they all reference the same instance. – Damien_The_Unbeliever Jul 24 '18 at 13:41
  • You only create one object and you put 3 reference of it into the same list. You need to new up 3 objects. – juharr Jul 24 '18 at 13:41
  • the issue with class , If use it I get the only last inserted item duplicated (n) times. – Mohammad Sufian Al-Omar Jul 24 '18 at 13:42
  • @MohammadSaffarini That's because you only create one instance of the class. You have to create a new instance for each new object otherwise you just keep changing the same object and you end up with duplicate references to the same object in your list. Structs on the other hand will copy when you assign them but then you run into the issues of why [mutable structs are evil](https://stackoverflow.com/questions/441309/why-are-mutable-structs-evil). – juharr Jul 24 '18 at 13:46

5 Answers5

2

Sounds like you're re-using the xItem object. You need to create a new one for each item in the list. The list is just a list of object references, and at the moment they all point to the same actual object. e.g. this code:

public static Item xItem = new Item();
public static List<Item> list = new List<Item>();

xItem.Code = "A";
xItem.Description = "A";
xItem.Price= "1";
xItem.Qty = "1";

list.Add(xItem);
//list now has 'A' with value of 1 in it..

xItem.Code = "B"
//without any further change, list will now have the same 
//item, so its Code will now be "B":
//this will be TRUE:
var listIsNowB = (list[0].Code == "B");

Instead, you need to do this:

xItem.Code = "A";
xItem.Description = "A";
xItem.Price= "1";
xItem.Qty = "1";

list.Add(xItem);

//we're now done with that *instance* of Item, so we now create a *new* one.
//we can re-use our variable without problem though.
xItem = new Item();
xItem.Code = "B";
xItem.Description = "B";
xItem.Price= "2";
xItem.Qty = "2";
//xItem is a new object, so this will work as you expect now.
list.Add(xItem);
GPW
  • 2,528
  • 1
  • 10
  • 22
1

For the struct version... there's no reason you shouldn't be able to change a value in a struct. Can you explain more completely the problem you had there? I suspect it has to do with using static, which seems like it has no place here... but there's not enough info in the question for us to know for sure.

For the class version, you need to create a new Item instance each time you want to add an entry:

//why are these static? That seems like a bad idea, but we lack enough context to know for sure
public static Item xItem;
public static List<Item> item = new List<Item>();

xItem = new Item();
xItem.Code = txtCode.Text;
xItem.Description = txtDescription.text;
xItem.Price= txtPrice.text;
xItem.Qty = txtQty.text;

This will let you add multiple class instances to the list... but if my suspicion is right, you'll then be in the same situation here you had when using struct, and I find it likely static is the culprit.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
1

This is due to reference- and value-types semantics. A reference-type (=class) is just a pointer to an instance. So when you pass an object to method, you actually provide a pointer to that object, not the actual object. This everything you change via that reference is reflected on all references to that instance.

In your case you have only a single reference that you use for different instance-semantics. Thus create a new instance instead of re-using the existing one:

public static Item xItem = new Item();
public static List<Item> item = new List<Item>();

...

xItem = new Item();
xItem.Code = txtCode.Text;
xItem.Description = txtDescription.text;
xItem.Price= txtPrice.text;
xItem.Qty = txtQty.text;

As an aside structs should usually be immutable. Thus whenever you intent to modify the instances state you should consider to use a class instead of a struct. For further reading about immutablilty you may read this post also: Why are C# structs immutable?

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Just to mention there are good reasons for 'struct' to be mutable. ‘ValueTuple‘ is mutable for performance reasons. Also there are much better reasons to make static variables immutable and read only.. – Filip Cordas Jul 24 '18 at 21:05
  • @FilipCordas You´re right, there might be reasonts to enable mutable structs, that´s why I wrote *usually*. However pure performance is usually a bad reason to. Instead think about the underlying *semantics*. – MakePeaceGreatAgain Jul 25 '18 at 06:43
  • I was more worried about that static variable he is using. That just looks like a disaster waiting to happen. If he makes anything immutable he should remove that completely. Also I think the only reason you should use structs is performance if you are fine with performance drops just use a class. – Filip Cordas Jul 25 '18 at 10:17
1

You're creating a static instance of Item and calling it xItem
You then set the properties of xItem and add this to your List - item

item now contains 1 item - xItem

You then set the properties of xItem again - and add to the list again.
Here's the catch. Your list now contains 2 items - 2 references to xItem - not 2 distinct objects, but the same object, twice.

... and again for a third time.

Your code needs to change to something like:

public static List<Item> item = new List<Item>();

//repeat this for each instance / 'version' of `Item` you want to add to your list.
// note the `new` keyword

var xItem = new Item();
xItem.Code = txtCode.Text;
xItem.Description = txtDescription.text;
xItem.Price= txtPrice.text;
xItem.Qty = txtQty.text;
item.Add(xItem);
Alex
  • 37,502
  • 51
  • 204
  • 332
1

class is a reference type so if you call a method if will only pass the reference to the object. struct is a value type that means it will create a whole copy of the object when you call a method unless you call it with in or ref. What you need to do is create a new instance of the class on every insert. like so

    item.Add(new Item
    {
        Code = txtCode.Text,
        ...
    });
Filip Cordas
  • 2,531
  • 1
  • 12
  • 23