-1

In the following program, I am unable to modify individual list items:

public class Program
{
    static void Main(string[] args)
    {
        List<Point2d> list = new List<Point2d>();

        list.Add(new Point2d(0, 0));
        list.Add(new Point2d(0, 1));

        foreach (Point2d item in list)
        {
            item.Print();
        }

        Point2d p = list[0];
        p.Set(-1, -1);

        foreach (Point2d item in list)
        {
            item.Print();
        }

        Console.ReadKey();
    }
}

Output:

(0,0)  (0,1)  (0,0)  (0,1)

My expected output was:

(0,0)  (0,1)  (-1,-1)  (0,1)

What am I doing incorrectly?


Relevant source code:

public struct Point2d : IEquatable<Point2d>
{
    public double X { get; set; }
    public double Y { get; set; }

    #region constructor
    public Point2d(double x, double y)
    {
        X = x;
        Y = y;
    }
    #endregion
    public void Print()
    {
        Console.Write("(");
        Console.Write(X);
        Console.Write(",");
        Console.Write(Y);
        Console.Write(")  ");
    }
    public void Set(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double GetDistance(Point2d otherPoint)
    {
        return Math.Sqrt(GetSquaredDistance(otherPoint));
    }

    public double GetSquaredDistance(Point2d otherPoint)
    {
        return ((otherPoint.X - X) * (otherPoint.X - X))
            + ((otherPoint.Y - Y) * (otherPoint.Y - Y));
    }

    public Point2d GetTranslated(Point2d center)
    {
        return new Point2d(X + center.X, Y + center.Y);
    }

    #region override string ToString()
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();

        sb.Append("(" + X + " , " + Y + ")");

        return sb.ToString();
    }
    #endregion

    #region equality comparison implementations
    public override bool Equals(object other)
    {
        if (!(other is Point2d)) return false;
        return Equals((Point2d)other); 
    }
    public bool Equals(Point2d other) 
    {
        return X == other.X && Y == other.Y;
    }
    public override int GetHashCode()
    {
        return (int)Math.Round(Y * 31.0 + X, 0); // 31 = some prime number
    }
    public static bool operator ==(Point2d a1, Point2d a2)
    {
        return a1.Equals(a2);
    }
    public static bool operator !=(Point2d a1, Point2d a2)
    {
        return !a1.Equals(a2);
    }
    #endregion
}
user366312
  • 16,949
  • 65
  • 235
  • 452
  • When you override `Equals` and `GetHashCode` you should make your object immutable (read only) as changing the values will change the hashcode and that will break dictionaries and other collections. – Enigmativity Apr 30 '22 at 00:26

1 Answers1

1

Point2d is a struct so when you did Point2d p = list[0]; you made a totally separate copy of the object. Your set only changed the copy not the original, you either need to make Point2d a class or add a list[0] = p; after the set.

Bugs like this is why it is recommended to make structs immutable and have no Set methods.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431