C#中的struct无法按预期工作

Pr.*_*dor 2 c# struct

我正在开发一个简单的应用程序,我有点困惑.我有一个简单struct Pointint xint y.而我用它Line

public class Line : Shape {

    public Line() {
        PointA = new Point(x: 0, y: 0);
        PointB = new Point(x: 0, y: 0);
    }

    public Point PointA { get; set; }
    public Point PointB { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在某个地方

var line = new Line();
line.PointB = new Point(x: 4, y: 2);
Console.WriteLine($"Line start at {line.PointA.GetX()}:{line.PointA.GetY()}; end at {line.PointB.GetX()}:{line.PointB.GetY()}");

for (int i = 0; i < 10; i++) {
    line.PointB.IncrementX();
    line.PointB.IncrementY();
}
Console.WriteLine($"Line start at {line.PointA.GetX()}:{line.PointA.GetY()}; end at {line.PointB.GetX()}:{line.PointB.GetY()}");
Run Code Online (Sandbox Code Playgroud)

这里需要增加xyPoint,但结果并没有改变:

行开始于0:0; 结束于4:2
线开始于0:0; 以4:2结束

我做错了什么?这看起来很奇怪.是否有一些特定的规则要struct在C#中使用.我知道这是一种价值类型,但我认为这对Point有利.所有示例都struct用于Point.请帮忙?

点:

public struct Point {

    private int _x;
    private int _y;

    public Point(int x, int y)
    : this() {
        _x = x;
        _y = y;
    }

    public void IncrementX() {
        _x++;
    }
    public void IncrementY() {
        _y++;
    }

    public int GetX() {
        return _x;
    }
    public int GetY() {
        return _y;
    }
}
Run Code Online (Sandbox Code Playgroud)

Ser*_*kiy 6

Struct是一种值类型.它通过值传递(即通过创建所有字段的副本)而不是传递对struct实例的引用.所以,当你这样做

line.PointB.IncrementX()
Run Code Online (Sandbox Code Playgroud)

当您调用PropertyB的getter时,它将返回存储在PropertyB支持字段中的Point 副本.然后你在副本上调用增量.因此原始价值将保持不变.

延伸阅读:值类型和引用类型,尤其是不同诱变只读的Structs其说

可变值类型是邪恶的.尝试始终使值类型不可变.


如果你想实际移动线点,你可以做什么?

  • 将点类型更改为class.然后它将通过引用传递,并且所有方法将在您存储的原始点上调用Line.

  • 将新(修改的)点实例分配给行

即你应该存储副本,更改它并分配回来

var point = line.PointB; // get copy
point.IncrementX();      // mutate copy
point.IncrementY();
line.PointB = point;     // assign copy of copy
Run Code Online (Sandbox Code Playgroud)

您还可以使Point结构不可变(对值类型可以做的最好的事情):

public struct Point
{
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; }
    public int Y { get; }

    public Point IncrementX() => new Point(X + 1, Y);
    public Point IncrementY() => new Point(X, Y + 1);
    public Point Move(int dx, int dy) => new Point(X + dx, Y + dy);
}
Run Code Online (Sandbox Code Playgroud)

现在改变位置看起来像

line.PointB = line.PointB.Move(1, 1);
Run Code Online (Sandbox Code Playgroud)