Changing the structure in a collection

I read about boxing in Richter’s book, and there is one thing that I don’t understand.
I successfully changed the struct in the object. But when I try to modify the struct in the collection, I have a problem.

 //my struct internal struct Point:IChangeBoxedPoint { public Int32 x, y; public void Change(Int32 x, Int32 y) { this.x = x; this.y = y; } public override string ToString() { return String.Format("{0}, {1}", this.x, this.y); } } public static void Main() { List<Point> a = new List<Point>(); Point p = new Point(); p.Change(1, 1); Console.WriteLine(p); //write 1, 1 object o = p; Console.WriteLine(o); //write 1, 1 ((Point)o).Change(2, 2); Console.WriteLine(o); //write 1, 1 ((IChangeBoxedPoint)o).Change(3, 3); Console.WriteLine(o); //write 3, 3 for (int i = 0; i < 10; i++) { px = py = i; a.Add(p); } Console.WriteLine(a[0]); //write 0, 0 ((IChangeBoxedPoint)a[0]).Change(300,300); Console.WriteLine(a[0]); //still writes 0,0 } 
+4
source share
3 answers

You must declare your collection as List<IChangeBoxedPoint> instead of List<Point> .

If you declare your list as a List<Point> , then your values ​​are put into a box / unpacked into and out of the interface, as others have already pointed out. But if you have a list of interfaces, then the values ​​are inserted into the box only when you add them to the list, which allows you to change them as needed.

+3
source

This is because struct are value types, such as primitives ( int , short , etc.). When you insert a struct into an object , it makes a copy of itself, which works separately. Here is a simple example to illustrate this.

 Point a = new Point(); Console.WriteLine(a); // 0, 0 a.Change(1, 1); Console.WriteLine(a); // 1, 1 object b = a; Console.WriteLine(b); // 1, 1 a.Change(2, 2); Console.WriteLine(a); // 2, 2 Console.WriteLine(b); // 1, 1 

class vs struct

If you want to use a reference type, you will not run into this problem, and your program will simply pass a link to your single object. Use class not struct if you want a reference type.

 internal class Point : IChangeBoxedPoint 

When to use struct

According to this other question which refers to MSDN .

Do not define the structure if the type has all of the following characteristics:

  • It logically represents a single value similar to primitive types (integer, double, etc.).
  • It has an instance size less than 16 bytes.
  • It is unchanging.
  • It does not need to be inserted into the box often.

If you do not know immutable means, the object cannot change. That way, you actually go against good practice by boxing a struct in an interface in an attempt to modify them.

Boxing at IChangeBoxedPoint

You can get around your problem with List<IChangeBoxedPoint> , but that just changes it to use a reference to your value type, so my question is why are you worried when you can just change your struct to class .

 List<IChangeBoxedPoint> a = new List<IChangeBoxedPoint>(); 

Further reading

+3
source

Seems correct:

 Console.WriteLine(a[0]); //write 0, 0 - 

just because your first element got i=0

And for this code

  ((IChangeBoxedPoint)a[0]).Change(300,300); 

Actually the first element does not change. He created a new instance of the Boxed Point object and changed its values.

Try changing it as

  Point newPoint = new Point(); newPoint.Change(300,300); a[0] = newPoint; Console.WriteLine(a[0]); 
0
source

All Articles