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);
}
7
  • sorry for that, now updated. Commented Jul 24, 2018 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. Commented Jul 24, 2018 at 13:39
  • You should probably not use struct unless you have read up on it, stick to class until now. Commented Jul 24, 2018 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. Commented Jul 24, 2018 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. Commented Jul 24, 2018 at 13:41

5 Answers 5

2

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. Thus everything you change via that reference is reflected on all references to that instance.

In your case you have only a single instance (just one single new call) and using that again and again. So what you should do is 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?

Sign up to request clarification or add additional context in comments.

4 Comments

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..
@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.
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.
Great answer, extra +1 for the link at the end.
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);

Comments

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);

Comments

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,
        ...
    });

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.