【问题标题】:Array and List discrepencies with structs数组和列表与结构的差异
【发布时间】:2012-12-05 20:48:58
【问题描述】:

在下面的代码中,结构是从数组和列表中获取的。当按索引获取项目时,数组似乎是通过引用来完成的,而列表似乎是通过值来完成的。有人能解释一下这背后的原因吗?

struct FloatPoint {
    public FloatPoint (float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    public float x, y, z;
}

class Test {

    public static int Main (string[] args) {
        FloatPoint[] points1 = { new FloatPoint(1, 2, 3) };

        var points2 = new System.Collections.Generic.List<FloatPoint>();
        points2.Add(new FloatPoint(1, 2, 3));

        points1[0].x = 0; // not an error
        points2[0].x = 0; // compile error

        return 0;
    }
}

将结构定义更改为类可以编译。

【问题讨论】:

  • 结构是值类型。列表重载 [] 运算符以返回 T 类型的对象。数组的特殊之处在于它们是内置的并且可以直接访问它们的元素:-)
  • 错误是什么,为什么这么说array appears to do it by reference whereas the list appears to do it by value
  • @BigM 确切的错误文本是:Cannot modify the return value of 'System.Collections.Generic.List&lt;ConsoleSandbox2.Program.FloatPoint&gt;.this[int]' because it is not a variable。至于他的报价,实际上或多或少是正确的。列表索引器返回一个副本,而不是数组访问。

标签: c# list struct


【解决方案1】:

当你得到一个结构体时,它总是按值来的。结构将被复制,您不会得到对它的引用。

不同的是,你可以直接在数组中访问sstruct,而不是在列表中。当您更改数组中结构中的属性时,您可以直接访问该属性,但要对列表执行相同操作,您必须获取结构,设置属性,然后将结构存储回列表中:

FloatPoint f = points2[0];
f.x = 0;
points2[0] = f;

早期版本的编译器可以让您编写已有的代码,但对于列表,它会生成类似于以下的代码:

FloatPoint f = points2[0];
f.x = 0;

即它会读取结构,更改它,然后默默地扔掉更改后的结构。在这种情况下,编译器已更改为出错。

【讨论】:

  • 出于这样的原因,mutable structs are considered evil by many。因此强烈建议您使您的结构不可变。你可以用readonlypublic readonly float x, y, z;来做到这一点。现在,您必须在每次要进行更改时将整个结构对象换成一个新对象。数组和列表也是如此:point[0] = new FloatPoint(0, point[0].y, point[0].z);
猜你喜欢
  • 2012-07-21
  • 2014-02-06
  • 2012-05-31
  • 2017-10-11
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
相关资源
最近更新 更多