18

I want to change the money value in my list, but I always get an error message:

Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable

What is wrong? How can I change the value?

struct AccountContainer
{
    public string Name;
    public int Age;
    public int Children;
    public int Money;

    public AccountContainer(string name, int age, int children, int money)
        : this()
    {
        this.Name = name;
        this.Age = age;
        this.Children = children;
        this.Money = money;
    }
}

List<AccountContainer> AccountList = new List<AccountContainer>();

AccountList.Add(new AccountContainer("Michael", 54, 3, 512913));
AccountList[0].Money = 547885;
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Leo
  • 267
  • 1
  • 4
  • 14

4 Answers4

21

You have declared AccountContainer as a struct. So

AccountList.Add(new AccountContainer("Michael", 54, 3, 512913));

creates a new instance of AccountContainer and adds a copy of that instance to the list; and

AccountList[0].Money = 547885;

retrieves a copy of the first item in the list, changes the Money field of the copy and discards the copy – the first item in the list remains unchanged. Since this is clearly not what you intended, the compiler warns you about this.

Solution: Do not create mutable structs. Create an immutable struct (i.e., one that cannot be changed after it has been created) or create a class.

dtb
  • 213,145
  • 36
  • 401
  • 431
12

You're using an evil mutable struct.

Change that to a class and everything will work fine.

Community
  • 1
  • 1
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 2
    Pity about `Point`, `Rectangle` and `Size`. At least Microsoft learnt a bit before making `Complex`. It would have been very annoying if *that* was mutable. – Matthew Watson May 21 '13 at 22:28
0

Probably not recommended, but it solves the problem:

AccountList.RemoveAt(0);
AccountList.Add(new AccountContainer("Michael", 54, 3, 547885));
bigtech
  • 464
  • 3
  • 6
  • 1
    Removing the first item in a list requires moving all of the items down an index, and then adding the item would require moving them back up. Instead you should just set the value at that index: `list[index] = new ...;` – Servy May 21 '13 at 21:14
0

Here's how I would solve it for your scenario (using the immutable struct method, rather than changing it to a class):

struct AccountContainer
{
    private readonly string name;
    private readonly int age;
    private readonly int children;
    private readonly int money;

    public AccountContainer(string name, int age, int children, int money)
        : this()
    {
        this.name = name;
        this.age = age;
        this.children = children;
        this.money = money;
    }

    public string Name
    {
        get
        {
            return this.name;
        }
    }

    public int Age
    {
        get
        {
            return this.age;
        }
    }

    public int Children
    {
        get
        {
            return this.children;
        }
    }

    public int Money
    {
        get
        {
            return this.money;
        }
    }
}

List<AccountContainer> AccountList = new List<AccountContainer>();

AccountList.Add(new AccountContainer("Michael", 54, 3, 512913));
AccountList[0] = new AccountContainer(
    AccountList[0].Name,
    AccountList[0].Age,
    AccountList[0].Children,
    547885);
Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
  • But does `AccountContainer` semantically represent a value? Ought it to be a struct? – Servy May 21 '13 at 21:15
  • @Servy That is an excellent question. If the example given of changing the `Money` is an oft-executed operation, the `AccountContainer` would likely be served better as as an entity (in DDD parlance, that is). My gut feel is that what is shown is a smaller cut of a bigger picture in which there might even be better opportunities for functional decomposition of entity vs. value data. – Jesse C. Slicer May 21 '13 at 21:22