Change the value of a property of a struct in C#

17,953

Solution 1

Structs can be either mutable or immutable, but they should be immutable according to many people.

Your example is a mutable struct.

Example of use:

var t = new Test();
// t.str is null, and t.int1 is 0

t.str = "changed!"; // OK

var t2 = t;
t2.int1 = 42;
// t.int1 is still 0

var li = new List<Test> { t, t2, };
t.int1 = 666;  // OK, but copy in li is unaffected

li[0].int1 = 911;  // compile-time error, not a variable

var t3 = t2;
bool checkA = (t3 == t2);  // compile-time error, you did not overload operator ==
bool checkB = t3.Equals(t2);  // OK, true, ValueType class overrides Equals for you
bool checkC = t2.Equals(t);  // OK, false
bool checkD = object.ReferenceEquals(t, t);  // false, two distinct boxes
                                             // same as (object)t==(object)t

By request, here is one way to make that struct immutable:

public struct Test 
{
    public string str { get; private set; }
    public int int1 { get; private set; }

    public Test(string str, int int1) : this()
    {
        this.str = str;
        this.int1 = int1;
    }
}
// if you introduce methods (other than constructors) that use the private setters,
// the struct will no longer be immutable

and here is another one:

public struct Test 
{
    readonly string m_str;
    readonly int m_int1;

    public string str { get { return m_str; } }
    public int int1 { get { return m_int1; } }

    public Test(string str, int int1)
    {
        m_str = str;
        m_int1 = int1;
    }
}

Solution 2

Can the values of 'str' and 'int1' be changed once they have been assigned a value?

Yes, struct's properties can be changed. structs are not immutable per se.

But it is considered a good design to make them unchangeable.

From Struct Design:

X DO NOT define mutable value types.

Mutable value types have several problems. For example, when a property getter returns a value type, the caller receives a copy. Because the copy is created implicitly, developers might not be aware that they are mutating the copy, and not the original value. Also, some languages (dynamic languages, in particular) have problems using mutable value types because even local variables, when dereferenced, cause a copy to be made.

Solution 3

structs are not automatically immutable, but because of certain issues it is strongly recommended to make them immutable yourself. You may be thinking of a similar problem where you can't change the properties of a struct if the struct is itself being accessed as a property (one of the reasons why it is recommended to make them immutable.) Using your Test example:

public struct Test {
   public string str { get; set; }
   public int int1 { get; set; }
}

// This works:
Test value = new Test();
value.str = "asdf";
value.int1 = 5;

// But this does NOT work.
Test TestProperty { get; set; }

TestProperty.str = "asdf";
TestProperty.int1 = 5;

The reason the second part doesn't work is that you are only getting a value copy by saying TestProperty, and then you set the value of the copy's properties, rather than the one in your object.

To make your struct immutable you would do something like this:

public struct Test {
   readonly string mStr;
   readonly int mInt1;

   public string str { get { return mStr; } }
   public int int1 { get { return mInt1; } }

   public Test(string pStr, int pInt1) {
      mStr = pStr;
      mInt1 = pInt1;
   }
}

You can create instances of Test, you can read their properties, but you can't change their properties, except by making a new instance.

Solution 4

Can definitely reassign new instance values to a struct. Immutability means that when you think you are changing the value, a new instance is created in memory and the previous copy is up for garbage collection.

Note that structs are immutable as a whole. Struct fields, in turn, can be mutable or immutable atomically. For your example, the string field is immutable, int is not.

Share:
17,953
h-rai
Author by

h-rai

Updated on June 04, 2022

Comments

  • h-rai
    h-rai almost 2 years

    I was reading a book and found out that structs are actually immutable objects. But they have getters and setters. I was wondering if a property of structs can be changed after it has been created.

    public struct Test 
    {
        public string str {get; set; }
        public int int1 {get; set; }
    }
    

    Can the values of 'str' and 'int1' be changed once they have been assigned a value?

  • h-rai
    h-rai almost 10 years
    I didn't know == operator could be overridden. I have Java background and all these techniques are alien to me. Also, can you demonstrate how to make my struct immutable?
  • h-rai
    h-rai almost 10 years
    So how can we explicitly make structs immutable?
  • Dave Cousineau
    Dave Cousineau almost 10 years
    @nick-s added an example
  • h-rai
    h-rai almost 10 years
    so in order to make the struct 'immutable', we need to remove the setters, make the fields 'readonly' and create a constructor to set the field values upon instantiation of the struct.
  • h-rai
    h-rai almost 10 years
    in the first example, what is the use of 'private set'?
  • Dave Cousineau
    Dave Cousineau almost 10 years
    @nick-s yeah, basically. "immutable" means "unchanging". so by doing this, once an instance exists, it will retain its state permanently. you can change instances, but you can't change the state of a particular instance.
  • Dave Cousineau
    Dave Cousineau almost 10 years
    While this will be oversimplified to word it this way (there are many exceptions), generally structs are not "up for garbage collection" since they are value types.
  • Dave Cousineau
    Dave Cousineau almost 10 years
    @nick-s reading a similar question made me think I should also point out: this also depends on the immutability of int and string. Since those are already immutable, then this struct as defined is fully immutable, but if you were to expose read only properties that returned mutable objects (like a List<T> for example), you would still be able to change the state of the other type.
  • Dai
    Dai almost 3 years
    @h-rai private set means the property str and int1 can only be assigned by members of struct Test. They're "auto-properties" as opposed to being public-fields. The field still exists but it's hidden and only accessible via the property. The Java equivalent would be private setStr(string value). That said, I'm going to update this answer's code to use modern C#.