-1

I have a structure that describe points:

public struct Point
{
    int _x;
    int _y;

    #region properties
    public int X
    {
        get { return _x; }
        set { _x = value; }
    }
    public int Y
    {
        get { return _y; }
        set { _y = value; }
    }
    #endregion
}

A lot of points are instantiated and stored in several Lists. Sometimes I have to change some Points and because to know in which List are stored the Points can be tricky, I wanted to create a List with all the Points instances thinking that a change in this list would affect other lists.

To be clear below some code to explain what I wanted to do:

List<Point> lstAllPoints = new List<Point>() { };
List<Point> lst1 = new List<Point>() { };
List<Point> lst2 = new List<Point>() { };

//some points are generated and stored in a list
for (int i = 0; i < 10; i++)
{
    Point pt = new Point();
    pt.X = i;
    pt.Y = i + 1;
    lstAllPoints.Add(pt);
    lst1.Add(pt);
}

//some other points are generated and stored in another list
for (int j = 0; j < 10; j++)
{
    Point pt = new Point();
    pt.X = j;
    pt.Y = j + 3;
    lstAllPoints.Add(pt);
    lst2.Add(pt);
}

Now my idea was to say if I change a Point in lstAllPoints then the corresponding point in others lists will be changed.

lstAllPoints[0].X = 400;
lstAllPoints[10].X = 800;

then: lst1[0].X is egal to 400, and lst2[0].X is egal to 800;

But because Point in this case is a structure in a list the reinitialisation "lstAllPoints[0].X = 400" does not work and because struct are value type the instances lstAllPoints[0] and lst1[0] are not the same instance: a change in lstAllPoints will not affect the Points in other lists.

The workaround I used was to change struct to class. A Point is then a reference type and everything works... perfect.

My question is: Is changing struct to class the only workaround? Are there no solutions to fill lists with the instance of the same struct instance, in such a way that changing a Point in a list change all other Points that share the same instance?

I think boxing/unboxing are not useful. I thought of pointers but then I have to work in an unsafe context and I don´t want to. I thought of using the keyword ref but it can only be applied to methods parameters:

//someting like
List<ref Point>...

Are there really no other solutions than changing struct to class?

Thanks in advance!

EDIT Here an edit to answer some of your comments. I am aware (or I guess I am aware) of the benefits of using struct in particular struct are put on the heap. Because I can have a lot of Points,it can be better to use structure in regards with performance concerns. I do not want to use pointer because I do not want to set an unsafe context. I do not have any reason not to use class. Nevertheless my question was more something for my culture because I was surprised not to be able to find a simple way to store a single struct instance in several lists.

Thank to all

eqtèöck
  • 971
  • 1
  • 13
  • 27

2 Answers2

1

You can write class-to-struct wrapper yourself :)

using System;
using System.Collections.Generic;

namespace Test {
  public class Ptr<T> where T : struct {
    public T Value { get; set; }
  }

  class Program {
    static void Main(string[] args) {
      var a = new List<Ptr<int>>();
      var b = new List<Ptr<int>>();

      var ptr = new Ptr<int> { Value = 7 };
      a.Add(ptr);
      b.Add(ptr);

      a[0].Value = 3;
      Console.Out.WriteLine(b[0].Value);
    }
  }
}
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • Note that this is going to perform *worse* than just making the underlying type a class instead of a struct. This should only be used if the type almost always requires value semantics and only occasionally requires reference semantics. – Servy Nov 13 '13 at 14:53
  • @Servy, do you mean that if a lot of instances are created and if the need of reference is rarely needed then the wrapper solution will be worse than a struct? – eqtèöck Nov 14 '13 at 07:04
1

If you want to use something as an entity, it needs to be a class type. I would suggest that what you should do is declare:

struct Point : IEquatable<Point> {
  public int X,Y;
  public Point(int x, int y) { X=x; Y=y; }
  public bool Equals(Point other) { return other.X==X && other.Y==Y; }
  public override bool Equals(Object obj) { return (obj is Point) && Equals((Point)Obj);
  public int GetHashCode() { return X*47 + Y; }
}
class MovableEntity 
{
  public Point Location;
  ExposedHolder(Point v) { Location = v; }
}

Then use variables of type Point in cases where you want something that encapsulate an X and a Y that behave independently of any other coordinate, and use variables of type MovableEntity in cases where you want to encapsulate a reference to an entity (such that changing the X field of one such variable will change the Y of the other).

With the types defined as shown, accessing the X and Y fields within the Location field of a MovableEntity will yield performance essentially identical to that of accessing such fields within a mutable Point class type, but will also allow the ability to say things like:

MovableEntity thing1, thing2;
...
thing1.Location = thing2.Location;

which would have the effect of setting the location of thing1 to match the present location of thing2, without disturbing the identity of thing1 or thing2. If MovableEntity had encapsulated X and Y directly, rather than using an exposed-field struct to do so, it would have been necessary to instead say something like:

thing1.X = thing2.X;
thing2.Y = thing2.Y;

Further, defining things as shown makes it possible to have a Dictionary<Point, somethingElse> which will protect any points used as keys against improper mutation.

Note that I have used public fields rather than properties. If the whole purpose of a structure is to encapsulate a set of related but independent variables, auto-properties will degrade performance without offering any real benefit. Further, auto-properties that expose structure types are much less efficient and awkward to work with than fields of such types and should be avoided except in cases where they offer semantic benefits sufficient to justify the cost.

supercat
  • 77,689
  • 9
  • 166
  • 211