Lists repeating last added item

Asked

Viewed 608 times

3

was studying about the lists in C# and I couldn’t understand what was wrong with my code (probably going to be very basic), all the items are the same as the last item added. I simplified the code to focus only on this part of the error, am I doing something wrong? What I saw to add is just use the List.Add(), but it’s not working. There’s also another class in the project, the class Itens, that has the variable nomes used in the code (and only this variable).

I left all the code on Main() to be a little less.

class Program
{
    static void Main(string[] args)
    {
        Itens itens = new Itens();
        List<Itens> list = new List<Itens>();

        itens.nome = "GPU";
        list.Add(itens);

        itens.nome = "Livro";
        list.Add(itens);

        for (int i = 0; i < list.Count; i++)
        {
            Console.WriteLine("Item: " + list[i].nome);
            //Aqui ele imprime tudo igual a ultima string adicionada
        }
        Console.ReadLine();
    }
}
  • 3

    This is because it inserts the reference to the object, not the object itself. When you insert, you need to create a new reference for the object Itens, with the new.

  • 2

    Imagine that each item is a box. What you will add is a reference to where this box is in the list (not the box itself). new does is "create a new box" to store this information and, consequently, a new reference to where you can find it.

  • 1

    Like the C pointers, right?

  • Basically, yes.

3 answers

5


using static System.Console;
using System.Collections.Generic;

public class Program {
    public static void Main(string[] args) {
        var list = new List<Item>() {
            new Item() { Nome = "GPU" },
            new Item() { Nome = "Livro" }
        };
        list.Add(new Item() { Nome = "Cadeira" });
        var item = new Item() { Nome = "Abóbora" };
        list.Add(item);
        var carro = new Item() { Nome = "Carro" };
        list.Add(carro);
        item = new Item() { Nome = "Outro objeto" };
        list.Add(item);
        list.Add(carro);
        for (int i = 0; i < list.Count; i++) {
            WriteLine($"Item: {list[i].Nome}");
        }
    }
}

public class Item {
    public string Nome;
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

I wasn’t adding different items, I was adding the same item, so it was only the last value. You have to create a new item to add to the list. When:

itens.nome = "Livro";

was changing the value of the same object created before, so the previous item pointed to this same object, but now with a new value.

This is because classes are types by reference, so what you have in the variable is a pointer to the object elsewhere. It seems like two things, but it’s the same. If it were one struct then it would be different, so that if it were an integer the same would not occur. Read more in What’s the difference between Struct and Class?.

Note that I have introduced new ways to write this. When you create the list you can already create the items inline and start the list already with the items.

Then I added a new item creating it inline again, that is, you do not need to create a variable for it. Nor do you need to assign values to its members after the object was created.

But I also did it with the variable creation if it is important. Again, you have to create a new object.

Let’s say you want another variable that holds an object and add a reference to this object in the list, I did this with carro.

Finally, I created a new item in the same variable. Of course the variable loses the reference to the previous object, but I showed that the important thing is to create the new object and not the variable.

I still added the variable carro again, even without touching the object. It is the same object being added, it is not another. If you touch this object, the two entries in the list will be affected because they reference the same object.

If you know the pointers of C, that’s it. Types by reference are always pointers to objects. Types by value are objects themselves. In C# it becomes more abstract, but the internal mechanism is equal to C.

Then note that your itens is not an object, is a variable that has a value, in the case of a pointer, the object is not in items. It is a common mistake for people to think that variables always hold objects. This is only true in types per value.

I changed the name of the class that makes more sense, it is only one item, the list is that are several items.

3

Try to add the items this way. I believe it will solve your problem.

list.Add(new item{ nome = "GPU" });
list.Add(new item{ nome = "Livro" });

2

It’s like Felipe Avelar spoke, you are just changing a property of the object itens and inserting it several times; would need to insert a different object for each position:

class Program
{
    static void Main(string[] args)
    {
        List<Itens> list = new List<Itens>();

        Itens itensGpu = new Itens();
        itens.nome = "GPU";
        list.Add(itensGpu);

        Itens itensLivro = new Itens();
        itens.nome = "Livro";
        list.Add(itensLivro);

        for (int i = 0; i < list.Count; i++)
        {
            Console.WriteLine("Item: " + list[i].nome);
            //Aqui ele imprime tudo igual a ultima string adicionada
        }
        Console.ReadLine();
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.