Indexer that points to item in struct array don't work

I have a class called Surface, in this class i have an array of type 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;
    }
}

However when i try to access the color using the indexer it don't get updated.

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

How can i solve this problem?

Jon Skeet
people
quotationmark

How can i solve this problem?

Well you could avoid creating mutable structs and exposing public fields, to start with. That's where the problem is coming from. Your code is effectively:

Color tmp = mySurface[x, y]; // Take a copy from the array...
tmp.Set(255); // This only affects the copy

To change the array, you'll need to call the setter on the indexer instead. For example:

Color tmp = mySurface[x, y];
tmp.Set(255);
mySurface[x, y] = tmp;

Assuming you actually have several values in your struct, it would be simpler if you'd make your struct immutable but provide methods that returned new values, just like DateTime.AddDays etc. Then you could write code like:

mySurface[x, y] = mySurface[x, y].WithRed(255);

Options if you really want to avoid using a setter:

  • Use ref return from C# 7: redefine your indexer to return a ref Color; although then you can't have a setter.
  • Make Color a class instead of a struct
  • Use a reference type inside Color, so you don't need to change the bits in the Color value itself. (This is really nasty - I'm not suggesting that.)

people

See more on this question at Stackoverflow