Value semantics in C # struct vs tuple

So, I'm taking my first steps in C # and doing a simple puzzle. When I was modeling the position of a tile, I wanted to have value semantics. So, as far as I can see, there are basically two ways to do this, with a structure or with a Tuple.

In the case of Tuple, my code looks like this:

public class TilePosition : Tuple<int,int>
{
    public int HComponent{get { return Item1; }}
    public int VComponent{get { return Item2; }}

   public TilePosition(int horizontalPosition, int verticalPosition)
        : base(horizontalPosition, verticalPosition)
    {
    }
}

      

A structural solution would look like this:

public struct TilePosition 
 {
    private readonly int hComponent;
    private readonly int vComponent;
    public int HComponent { get { return hComponent; } }
    public int VComponent { get { return vComponent; } }

   public TilePosition(int hComponent, int vComponent)
    {
        this.hComponent = hComponent;
        this.vComponent = vComponent;
    }

   public static bool operator ==(TilePosition position1, TilePosition position2)
    {
        return position1.Equals(position2);
    }

   public static bool operator !=(TilePosition position1, TilePosition position2)
    {
        return !(position1 == position2);
    }
}

      

A tuple is a conciser, but it provides Item1

and Item2

that would get confused in the public API, although I added the H and V component properties around them.

The structure needs more code and I get a compiler warning about how I should override Equals and GetHashCode because I override ==

and !=

, but if I do that, I get nothing from using the structure (semantic and syntactically) because that it is exactly the same code with a regular class.

So, are there any advantages to using a struct over a Tuple subclass other than the lack of noise on Item properties?

Will my solution behave as I expect, or is there some nuance I should be aware of?

+3


source to share


3 answers


(As an aside, it would be nice to implement IEquatable<TilePosition>

in both cases - especially in the case of a struct to avoid boxing.)

So, are there any advantages to using a struct over a Tuple subclass other than the lack of noise on Item properties?

Given that it is immutable, in both cases you have rough "value semantics" in both cases, but there are still differences ...



  • An instance of a class type requires space on the heap (assuming the CLR does not detect escape identification); a struct value can in some cases use a stack
  • Passing a class type value means only passing a reference (4 bytes or 8 bytes depending on the CLR architecture); passing a value of type struct does indeed pass values โ€‹โ€‹(so 8 bytes)
  • The version of the class has a null

    valid value; in the struct type version, you will need to use TilePosition?

    to indicate the possibly missing value
  • In the version, struct is new TilePosition()

    legal and will have values โ€‹โ€‹of 0 for both fields (and this will be the default, for example, for fields and array elements).
  • As you didn't seal your class, someone might have created a mutable subclass; therefore, it is not safe for the client to assume it is completely immutable. (You should probably seal it ...)
  • You can use your class type with whatever code you use Tuple<,>

    , whereas this is clearly not the case for the struct type
  • The meaning ==

    will differ between the two types. Even if you overload ==

    on a class type, the caller can still just compare references. And in the case of construct, you could still end up comparing box references, no use.

These are just differences, of course, whether they count as benefits for one approach or the other depends on your requirements.

+8


source


How about using a jagged array and storing the item in each field. This will follow the puzzle more closely:



  • Tiles and their space are 1: 1 mapping. Thus, each tile / space can only have one space / tile.
  • No need to compare tile components.
  • Moving tiles is easy, for example

        if (fields[x, y] = null)
        {
            fields[x, y] = fields[oldX, oldY];
            fields[oldX, oldY] = null;
        }
    
          

0


source


It's best to do it right and do all the work. If you want a struct, not a class (which may be right for you), here's an example implementation:

public struct TilePosition: IEquatable<TilePosition>
{
    public TilePosition(int horizontalPosition, int verticalPosition)
    {
        _x = horizontalPosition;
        _y = verticalPosition;
    }

    public int HComponent
    {
        get
        {
            return _x;
        }
    }

    public int VComponent
    {
        get
        {
            return _y;
        }
    }

    public static bool operator == (TilePosition lhs, TilePosition rhs)
    {
        return lhs.Equals(rhs);
    }

    public static bool operator != (TilePosition lhs, TilePosition rhs)
    {
        return !lhs.Equals(rhs);
    }

    public bool Equals(TilePosition other)
    {
        return (_x == other._x) && (_y == other._y);
    }

    public override bool Equals(object obj)
    {
        return obj is TilePosition && Equals((TilePosition)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (_x*397) ^ _y;
        }
    }

    private readonly int _x;
    private readonly int _y;
}

      

0


source







All Articles