Jump to content
  • Advertisement
Sign in to follow this  

[.net] Lists of structs or classes - assigning values problem

This topic is 3435 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

how to assign value to list elements of structs or classes public List<Vector2> vertices = new List<Vector2>(); foreach (Vector2 v in this.vertices) { v.Assign3DCoordinates(1.3f, 1.3f, 1.3f); //not working v.X = 1.3f //also not working } public struct Vector2 { public float X; public float Y; public float Z; public void Assign3DCoordinates(float xx, float yy, float zz) { this.X = xx; this.Y = yy; this.Z = zz; } }

Share this post


Link to post
Share on other sites
Advertisement
It has something to do with the struct being copied directly to the stack rather than giving you a handle to the stored object. I don't remember precisely why this is (and I should!) but you have to do this:

Vector2 vector = vertices;
vector.Assign3DCoordinates(1.3f, 1.3f, 1.3f);
vertices = vector;

Of course, you need a for loop to do this, you can't modify a collection when using foreach.

edit:
Or of course you can make Vector2 a class, which will solve the problem, but given your struct has the word "Vector" in it, I assume you're doing this for speed. Note that the above has to be done in XNA as well, as all the vectors are structs. I always find it a pain to have to take out a rectangle, change the values I want then stomp the old copy with the new.

Share this post


Link to post
Share on other sites
It's because Vector2 is a value-type. If you go:

Vector2 v1 = new Vector(1,2,3);
Vector2 v2 = v1;
v1.X = 123;


Then v2 will still have the original value -- it's not a reference to the same object, it's a totally different object. So in your foreach loop, the Vector2 v that you've created is a different instance of Vector2 than what's in your list. It's a little hard to explain, but here's an example that should do what you want:


public struct Vector2
{
public float X;
public float Y;
public float Z;

public Vector2(float xx, float yy, float zz)
{
this.X = xx;
this.Y = yy;
this.Z = zz;
}
}

public void Foo()
{
var vertices = new List<Vector2>();
vertices.Add(new Vector2());
vertices.Add(new Vector2());

for(int i = 0; i < vertices.Count; i++)
{
vertices = new Vector2(1, 2, 3);
}
}



As an aside, why do you have a "Vector2" class with three elements?

Share this post


Link to post
Share on other sites
You cannot modify a value type through the enumerator interface.

You can get the behavior you want by doing as follows, although it won't work on every collection type:

List<Vector2> vertices = new List<Vector2>();

for (int i = 0; i < vertices.Count; ++i)
{
Vector2 vertex = vertices;
vertex.Assign3DCoordinates(1.3f, 1.3f, 1.3f);
vertex.X = 1.3f;
vertices = vertex;
// Note that you still can't do the following if X is a field:
// vertices.X = 1.3f;
// Also note that the following only modifies a copy of vertices :
// vertices.Assign3DCoordinates(1.3f, 1.3f, 1.3f);
}






[Edit] Argh... beaten to it... twice!
[Edit2] In fact, more generally, you cannot directly assign the fields of a property which's type is a value type, even if it has both a getter and a setter. You have call the getter to get a copy, modify the copy and set it back using the setter. I don't know why the compiler doesn't do that automatically...

Share this post


Link to post
Share on other sites
Thank you all! You helped me!
It works even though I don't understand the reason why they make it this way... On large lists with 10M points It should make speed difference of copying each point back and forth 2 times (i don't need great performance but still...)

Share this post


Link to post
Share on other sites
The reason has to do with the way CPUs work. A value type can be put in registers or on the stack by the compiler, which is much faster than accessing the global heap (where classes are stored). Well, that's a really really really simplified picture of it anyway, but if you keep your structures to <= 16 bytes the compiler can help you make them faster.

I just want to clarify that all of the above posts don't apply to classes, though you can do that if you want, but vertices.Assign3DCoordinates() call will work if you have a list of classes.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!