2

假设我有一个结构:

struct Vector
{
    public int X, Y;

    // ...
    // some other stuff
}

和一个班级:

class Map
{
    public Vector this[int i]
    {
        get
        {
            return elements[i];
        }
        set
        {
            elements[i] = value;
        }
    }

    private Vector[] elements

    // ...
    // some other stuff
}

我希望能够做类似的事情:map[index].X = 0;但我不能,因为返回值不是变量。

如果可能的话,我该怎么做?

4

4 回答 4

4

您应该避免使用可变结构。

如果您希望您的类型是可变的,请改用一个类。

class Vector
{
    public int X { get; set; } // Use public properties instead of public fields!
    public int Y { get; set; }

    // ...
    // some other stuff
}

如果要使用结构,请使其不可变:

struct Vector
{
    private readonly int x;  // Immutable types should have readonly fields.
    private readonly int y;

    public int X { get { return x; }} // No setter.
    public int Y { get { return y; }}

    // ...
    // some other stuff
}
于 2012-05-15T20:09:14.560 回答
3

编译器会阻止您这样做,因为索引器返回对象的副本而不是引用(结构是按值传递的)。索引器返回一个副本,您修改此副本,您根本看不到任何结果。编译器可以帮助您避免这种情况。

如果你想处理这种情况,你应该改用 class 或者改变你处理 Vector 的方式。你不应该修改它的值,而是在构造函数中初始化它的值,更多关于这个主题:为什么可变结构是“邪恶的”?.

于 2012-05-15T20:11:16.540 回答
1

Although generic classes work pretty well for many purposes, they do not provide any reasonable way to access structs by reference. This is unfortunate since in many cases a collection of structs would offer better performance (both reduced memory footprint and improved cache locality) and clearer semantics than a collection of class objects. When using arrays of structs, one can use a statement like ArrayOfRectangle[5].Width += 3; with very clear effect: it will update field X of ArrayOfRectangle[5] but it will not affect field X of any other storage location of type Rectangle. The only things one needs to know to be certain of that are that ArrayOfRectangle is a Rectangle[], and Rectangle is a struct with a public int field X. If Rectangle were a class, and the instance held in ArrayOfRectangle[5] had ever been exposed to the outside world, could be difficult or impossible to determine whether the instance referred to by ArrayOfRectangle[5] was also held by some other code which was expecting that field X of its instance wouldn't change. Such problems are avoided when using structures.

Given the way .net's collections are implemented, the best one can do is usually to make a copy of a struct, modify it, and store it back. Doing that is somewhat icky, but for structs that aren't too big, the improved memory footprint and cache locality achieved by using value types may outweigh the extra code to explicitly copy objects from and to the data structures. It will almost certainly be a major win compared with using immutable class types.

Incidentally, what I'd like to see would be for collections to expose methods like: OperateOnElement<paramType>(int index, ref T element, ref paramType param, ActionByRef<T,paramType> proc) which would call proc with the appropriate element of the collection along with the passed-in parameter. Such routines could in many cases be called without having to create closures; if such a pattern were standardized, compilers could even use it to auto-generate field-update code nicely.

于 2012-05-16T00:26:28.373 回答
1
  • 将 Vector 定义为类,或
  • 将值存储在临时变量中

    var v = 地图[索引]; vX = 0; 地图[索引] = v;

或者

  • 添加函数来改变 map[index] = map[index].Offset()

或者

  • 让 [] 运算符返回一个 setter 类

    类设置器 { 向量 [] 数据;整数索引;公共双 X { 获取 { 返回数据 [索引]; } set { Data[Index] = new Vector(value, Data[Index].Y); }}}

    public Setter this[int i] { get { return new Setter() { Data = elements, Index= i }; } }

于 2012-05-15T20:09:25.827 回答