为什么我不能修改单个列表项?[复制]

Why cannot I modify individual list items? [duplicate]

提问人:user366312 提问时间:4/30/2022 更新时间:4/30/2022 访问量:29

问:

在以下程序中,我无法修改单个列表项:

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();
    }
}

输出:

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

我的预期输出是:

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

我做错了什么?


相关源代码:

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
}
c# 列表 可变

评论

0赞 Enigmativity 4/30/2022
当你覆盖时,你应该使你的对象不可变(只读),因为更改值将改变哈希码,这将破坏字典和其他集合。EqualsGetHashCode

答:

1赞 Scott Chamberlain 4/30/2022 #1

Point2d 是一个结构体,所以当你这样做时,你做了一个完全独立的对象副本。您的集合仅更改了副本而不是原始副本,您要么需要将 Point2d 设为类,要么在集合后添加一个。Point2d p = list[0];list[0] = p;

像这样的错误就是为什么建议使结构不可变并且没有 Set 方法的原因。