C# 指向结构数组don';行不通

C# 指向结构数组don';行不通,c#,arrays,struct,C#,Arrays,Struct,我有一个名为Surface的类,在这个类中我有一个struct Color类型的数组 public class Surface { private Color[,] pixels; public Color this[int x, int y] { get { return pixels[y, x]; } } } [StructLayout(LayoutKind.Explicit)] public struct Color { [Fie

我有一个名为Surface的类,在这个类中我有一个struct Color类型的数组

public class Surface
{
    private Color[,] pixels;

    public Color this[int x, int y]
    {
        get { return pixels[y, x]; }
    }
}

[StructLayout(LayoutKind.Explicit)]
public struct Color
{
    [FieldOffset(0)]
    public byte R;

    public void Set(byte r)
    {
        R = r;
    }
}
但是,当我尝试使用索引器访问颜色时,它不会得到更新

mySurface[x, y].Set(255); // Will not work, i don't get an error but the color don't get updated.

如何解决此问题?

结构是值类型,因此,如果通过调用
像素[y,x]
从数组中获取它,实际上将创建结构的副本以更改其上的字段


另请参见

结构是值类型,因此,如果您通过调用
像素[y,x]
从数组中获取它,您将实际创建结构的副本以更改其上的字段

另见

我怎样才能解决这个问题

首先,您可以避免创建可变结构和公开公共字段。这就是问题的根源。您的代码有效地:

Color tmp = mySurface[x, y]; // Take a copy from the array...
tmp.Set(255); // This only affects the copy
要更改数组,您需要调用索引器上的setter。例如:

Color tmp = mySurface[x, y];
tmp.Set(255);
mySurface[x, y] = tmp;
假设您的结构中确实有多个值,如果您使结构不可变,但提供返回新值的方法(如
DateTime.AddDays
等),则会更简单。然后您可以编写如下代码:

mySurface[x, y] = mySurface[x, y].WithRed(255);
如果确实要避免使用setter,请选择以下选项:

  • 使用C#7中的
    ref return
    :重新定义索引器以返回
    ref Color
    ;虽然那样你就没有二传手了
  • 使
    Color
    成为类而不是结构
  • Color
    中使用引用类型,因此无需更改
    Color
    值本身中的位。(这真的很糟糕——我不是在暗示。)
我怎样才能解决这个问题

首先,您可以避免创建可变结构和公开公共字段。这就是问题的根源。您的代码有效地:

Color tmp = mySurface[x, y]; // Take a copy from the array...
tmp.Set(255); // This only affects the copy
要更改数组,您需要调用索引器上的setter。例如:

Color tmp = mySurface[x, y];
tmp.Set(255);
mySurface[x, y] = tmp;
假设您的结构中确实有多个值,如果您使结构不可变,但提供返回新值的方法(如
DateTime.AddDays
等),则会更简单。然后您可以编写如下代码:

mySurface[x, y] = mySurface[x, y].WithRed(255);
如果确实要避免使用setter,请选择以下选项:

  • 使用C#7中的
    ref return
    :重新定义索引器以返回
    ref Color
    ;虽然那样你就没有二传手了
  • 使
    Color
    成为类而不是结构
  • Color
    中使用引用类型,因此无需更改
    Color
    值本身中的位。(这真的很糟糕——我不是在暗示。)

您刚刚发现为什么要尝试
var temp=mySurface[x,y];温度设置(255);mySurface[x,y]=温度var temp=mySurface[x,y];温度设置(255);mySurface[x,y]=温度相反。与其他问题相关的是,它没有更改创建副本的属性(不是在
Color
中有属性)-它是索引器。你是对的,Jon。我没解释清楚。。。我对答案进行了编辑以使其更加正确。它并没有更改创建副本的属性(不是因为
Color
中有属性)-它是索引器。你是对的,Jon。我没解释清楚。。。我对答案进行了编辑以使其更加正确。旁白:新的ValueTuple结构既公开公共字段,又是可变的。为什么呢一些性能注意事项?如果通过引用返回
Color
,也可以避免调用setter:
public ref Color this[int x,int y]=>ref pixels[y,x]。最终使用了ref解决方案。附带问题:新的ValueTuple结构既公开公共字段,又是可变的。为什么呢一些性能注意事项?如果通过引用返回
Color
,也可以避免调用setter:
public ref Color this[int x,int y]=>ref pixels[y,x]。最终使用ref解决方案。