I'm working on some simulation code in C#, and I have some code along the lines of:
public void predict(Point start, Point end)开发者_Python百科
{
end.velocity = start.velocity + dt * end.acceleration;
end.position = start.position + dt * end.velocity;
}
Where position, velocity, acceleration are some vector data types I defined with associated operators.
As well as code where I'm doing:
StartPoint = EndPoint;
EndPoint = CurrentPoint;
With the *Points being instances of Points that have several primitive (double) and non-primitive (Vector) data types.
I'm running into the (obvious) issue that the above code, most likely will simply just set StartPoint to point to the data that was previously EndPoint, and EndPoint will point to CurrentPoint.
Meaning, if I modify CurrentPoint again I'll end up accidentally modifying EndPoint.
In C++ this is simple to prevent since I can define my assignment operator to do a deep copy of the underlying data within my Point objects. How can I prevent this in C#?
Thanks for any help!
Edit: The Vector class is defined as
[Serializable]
public class Vector
{
private Double[] data = new Double[Constants.Dimensions];
... snip ...
public static Vector operator +(Vector lhs, Vector rhs)
{
Vector result = new Vector();
for (UInt32 i = 0; i < Constants.dimensions; i++)
result[i] = lhs[i] + rhs[i];
return result;
}
lots more code here
}
This is one of the nastiest problems with the C# design IMHO.
If 'Point' is a struct (value), then a memberwise copy will be made, so x = y
will make an independent copy of y. But if it is a class (reference), x = y
will simply point the reference x to the same storage used for y, so the two will simply become different 'aliases' for the same data.
The two solutions I know of for your issue are:
Use a struct. This will give you the value-type behaviour that you expect for maths classes. To keep your code efficient you may then need to pass by reference everywhere to avoid the structs being copied continually.
Use a class, but be very very careful when using = to make sure you retain an independent copy of the data. You'll need to change
x = y
to something else, e.g.x = new Point(y);
.
Could you use Clone(), and then implement the deep-copy how you need it?
StartPoint = EndPoint;
EndPoint = (Point)CurrentPoint.Clone();
You want to pass by reference. Your methods are currently passing by value, meaning the value of your variables are being copied. The method will always be working with a copy of the data.
To pass by reference do the following:
public void predict(ref Point start, ref Point end)
{
end.velocity = start.velocity + dt * end.acceleration;
end.position = start.position + dt * end.velocity;
}
You will then have to call the method with the ref keyword like so:
predict(ref start, ref end);
精彩评论