Hao Wooi Lim
Hao Wooi Lim

Reputation: 3988

Why state in a structs in a List cannot be change?

I know this sounded stupid. But I gotta be doing something wrong here.

Say,

struct lala
{
    private bool state1;

    public lala(bool state1)
    {
        this.state1 = state1;
    }

    public void SetState1ToTrue()
    {
        this.state1 = true;
    }

    public bool GetState1()
    {
        return this.state1;
    }
}

Then somewhere...

List<lala> lalas = new List<lala>();

lalas.Add(new lala(false));
lalas.Add(new lala(false));

lalas[0].SetState1ToTrue();

// Why is it False???
Console.WriteLine(lalas[0].GetState1());

Are there any workarounds to this except changing it to:

List<lala> lalas = new List<lala>();

lalas.Add(new lala(false));
lalas.Add(new lala(false));

lala newLala = lalas[0];
newLala.SetState1ToTrue();
lalas[0] = newLala;

// It's True, finally.
Console.WriteLine(lalas[0].GetState1());

Which looked awful, unelegant and wasted 2 lines of code. If there's any Linq-ish or Functional Programming-ish way in say 1 line of code that would be awesome.

Upvotes: 0

Views: 145

Answers (5)

Daniel Earwicker
Daniel Earwicker

Reputation: 116724

Without changing it to a class (which is probably the right answer), the Linq-ish approach you asked for would be make the struct immutable, and so the "state changing" method would instead return a modified version. That way, you can't use it wrong.

struct lala
{
    private readonly bool state1; // note: readonly

    public lala(bool state1)
    {
        this.state1 = state1;
    }

    public lala SetState1ToTrue()
    {
        return new lala(true); // would copy any other fields, unchanged
    }

    public bool GetState1()
    {
        return this.state1;
    }
}

Then you could "change" a whole list in one go:

List<lala> changed = original.Select(l => l.SetState1ToTrue()).ToList();

Though really you've created a brand new list - but that's structs for you.

Upvotes: 0

Seibar
Seibar

Reputation: 70353

Because struct is always a value type, it is inherently immutable. This means that instead of doing:

lalas[0].SetState1ToTrue();

You should do:

lalas[0] = lalas[0].SetState1ToTrue();

There is an excellent article by Jon Skeet that explains in detail the differences between value types and reference types.

Upvotes: 0

RossFabricant
RossFabricant

Reputation: 12492

Structs are value types, so they are passed by value. That means that lalas[0] gives you a copy of the struct in lalas. You are changing a copy, so the original is unchanged.

Upvotes: 1

David M
David M

Reputation: 72930

The problem is in this line:

lalas[0].SetState1ToTrue();

The first part, lalas[0], retrieves the first lala from the list, and does so as a new copy of it in an implicit variable. So your SetState1ToTrue operates on a lala that is then immediately discarded, and the one in the list remains the same. It's the same as doing this:

lala newLala = lalas[0];
newLala.SetState1ToTrue();

If you make lala a class not a struct, so that it becomes a reference type, then the temporary variable (explicit or implicit) is a reference to the lala within the list.

Upvotes: 6

Adam Robinson
Adam Robinson

Reputation: 185693

Your issue that is that you're dealing with a struct, which is a value type, rather than a class, which is a reference type. The behavior you're expecting is that of a reference type. I would suggest just changing your declaration to a class (just given the simple example) and you shouldn't have an issue.

Upvotes: 0

Related Questions