Reputation: 681
I am starting to learn C# and could do with the following result explained to me regarding value types and reference types. My understanding is that ints and structs are value types so therefore get copied in assignments and strings and classes are reference types so only the reference is copied and not the underlying object. This is my code to test this:
struct MyStruct
{
public class C
{
public string _string;
};
public C _c;
public string _string;
public int _a;
public MyStruct(int a, string s)
{
_a = a;
_c = new C();
_c._string = s;
_string = s;
}
};
public static void Main(string[] args)
{
MyStruct stru = new MyStruct(4, "Hello");
MyStruct stru2 = stru;
stru2._a = 5;
stru2._string = "World";
stru2._c._string = "World";
Console.WriteLine("Stru _a: " + stru._a);
Console.WriteLine("Stru2 _a: " + stru2._a);
Console.WriteLine("Stru _string: " + stru._string);
Console.WriteLine("Stru2 _string: " + stru2._string);
Console.WriteLine("Stru C _string: " + stru._c._string);
Console.WriteLine("Stru2 C _string: " + stru2._c._string);
}
In this contrived example I get the following output:
Stru _a: 4
Stru2 _a: 5
Stru _string: Hello
Stru2 _string: World
Stru C _string: World
Stru2 C _string: World
The int variable _a makes perfect sense. It's a value type so it gets copied and not referenced, hence the change to "Stru2" doesn't effect "Stru". The _string surprised me as it's a reference type I expected both values to be output as "World". I expected the _c._string to both be "World" like it is, however I don't understand why the behaviour is different to the _string not part of the class. Any explanation would be appreciated. Thanks!
Upvotes: 1
Views: 125
Reputation: 2703
struct MyStruct // Value type
{
public class MyClass // Ref type
{
public string myClassString;
};
public MyStruct(int a, string s)
{
myStrucInt = a;
myClass = new MyClass();
myClass.myClassString = s;
myStractString = s;
}
public MyClass myClass;
public string myStractString;
public int myStrucInt;
};
public static void Main(string[] args)
{
MyStruct stru = new MyStruct(4, "Hello"); // val type
MyStruct stru2 = stru; // val type (makes a copy for stru)
stru2.myStrucInt = 5;
stru2.myStractString = "World";
stru2.myClass.myClassString = "World";
Console.WriteLine("Stru _a: " + stru.myStrucInt); // 4
Console.WriteLine("Stru2 _a: " + stru2.myStrucInt); // 5
Console.WriteLine("Stru _string: " + stru.myStractString); // Hello is original value of stru (struct is value type)
Console.WriteLine("Stru2 _string: " + stru2.myStractString); // World
Console.WriteLine("Stru C _string: " + stru.myClass.myClassString); // World
Console.WriteLine("Stru2 C _string: " + stru2.myClass.myClassString); // World
}
Upvotes: 1
Reputation: 387557
My understanding is that ints and structs are value types so therefore get copied in assignments and strings and classes are reference types so only the reference is copied and not the underlying object.
That is correct. But by the same logic, when you copy a struct that contains a reference type member, its reference value is copied and not the underlying value. So when you make a copy of your struct, all its values are copied to the copied struct: The int value, the string reference, and the C
reference since C
is a reference type.
So both struct copies contain a reference to the same underlying C
object. So if you mutate that C
object, changes will appear in both structs since they both refer to the same object.
For the _string
member however, you are replacing the reference when you do stru2._string = "World"
. This changes the stru2
struct but because that is a full copy of stru
, the original struct is not affected.
Just because one type is a value type (or a reference type) that does not mean that its members are under the same effect either.
Upvotes: 1
Reputation: 56
I think it’s because string is immutable Any string variable that gets the same value point to the same shared place in memory. So when you set stru2 = stru, stru._string and stru2._string point to the same place, when you set stru2._string = "World", stru2._string points to a new place but not stru._string. As for _c the situation is different: since stru._c and stru2._c point to the same place, any change of any property of stru2._c will change any property of stru._c.
Upvotes: 0