简体   繁体   English

C#中的struct不能按预期工作

[英]struct in C# doesn't work as expected

I'm working on a simple application and I'm a little confused. 我正在开发一个简单的应用程序,我有些困惑。 I have a simple struct Point with int x and int y . 我有一个简单的struct Pointint xint y And I use it for Line 我用它做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; }
}

and somewhere 在某处

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

Here need to increment x and y of Point but result doesn't change: 这里需要增加Point xy ,但结果不会改变:

Line start at 0:0; 行从0:0开始; end at 4:2 在4:2结束
Line start at 0:0; 行从0:0开始; end at 4:2 在4:2结束

What I'm doing wrong? 我做错了什么? It seems strange. 好像很奇怪 Are there some specific rules to use struct in C#. 在C#中使用struct是否有一些特定的规则。 I know that this is a value type but I think it is a good for Point. 我知道这是一个值类型,但我认为这对Point是个好处。 All examples uses struct for Point. 所有示例都将struct用于Point。 Please help? 请帮忙?

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

Struct is a value type. 结构是一种值类型。 And it is passed by value (ie by creating copy of all fields) instead of passing reference to struct instance. 它通过值(即通过创建所有字段的副本)传递,而不是将引用传递给struct实例。 So when you do 所以当你这样做

line.PointB.IncrementX()

When you call getter of PropertyB, it returns copy of Point which is stored at PropertyB backing field. 当您调用PropertyB的getter时,它将返回Point的副本 ,该副本存储在PropertyB的支持字段中。 And then you call increment on copy . 然后在副本上调用增量。 Thus original value will stay unchanged. 因此,原始值将保持不变。

Further reading: Value and Reference Types and especially Mutating Readonly Structs which says 进一步阅读: 值和引用类型 ,尤其是变异只读结构 ,其中指出

mutable value types are evil. 可变值类型是邪恶的。 Try to always make value types immutable. 尝试使值类型始终不变。


What you can do if you want to actually move line point? 如果要实际移动线点该怎么办?

  • Change Point type to class . 将Point类型更改为class Then it will be passed by reference, and all methods will be called on original point which you store in Line . 然后它将通过引用传递,并且所有方法都将在存储在Line原始点上调用。

  • Assign new (modified) point instance to line 将新的(修改的)点实例分配给线

Ie you should store copy, change it and assign back 也就是说,您应该存储副本,更改副本并分配回去

var point = line.PointB; // get copy
point.IncrementX();      // mutate copy
point.IncrementY();
line.PointB = point;     // assign copy of copy

You can also make your Point struct immutable (the best thing you can do for value types): 您还可以使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);
}

And now changing location will look like 现在更改位置看起来像

line.PointB = line.PointB.Move(1, 1);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM