如何让列表共享相同的结构实例?

时间:2013-11-12 13:49:56

标签: c# list struct instance

我有一个描述点的结构:

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
}

许多点被实例化并存储在多个列表中。有时我必须更改一些Points,因为要知道在哪个List中存储点可能很棘手,我想创建一个包含所有Points实例的List,认为此列表中的更改会影响其他列表。

要清楚下面的一些代码来解释我想要做的事情:

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);
}

现在我的想法是说如果我在lstAllPoints中更改一个Point,那么其他列表中的对应点将会被更改。

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

然后: lst1 [0] .X对400是egal,而lst2 [0] .X对800是egal;

但是因为在这种情况下Point是一个列表中的结构,重新初始化“lstAllPoints [0] .X = 400”不起作用,并且因为struct是值类型,实例lstAllPoints [0]和lst1 [0]不是同一实例:lstAllPoints的更改不会影响其他列表中的Points。

我使用的解决方法是将struct更改为class。然后,Point就是一个引用类型,一切正常......完美。

我的问题是:将结构更改为类是唯一的解决方法吗?是否没有解决方案来填充具有相同结构实例的实例的列表,这样更改列表中的Point会更改共享同一实例的所有其他点?

我认为装箱/拆箱没用。我想到了指针,但后来我必须在一个不安全的环境中工作,我不想这样做。我想过使用关键字ref,但它只能应用于方法参数:

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

除了将struct更改为class之外,真的没有其他解决方案吗?

提前致谢!

修改 这是一个回答你的一些评论的编辑。 我知道(或者我想我知道)在特定结构中使用struct的好处是放在堆上。因为我可以拥有很多积分,所以在性能方面考虑使用结构会更好。 我不想使用指针,因为我不想设置不安全的上下文。 我没有任何理由不上课。 然而,我的问题更多的是我的文化,因为我很惊讶不能找到一个简单的方法将单个结构实例存储在几个列表中。

感谢所有

2 个答案:

答案 0 :(得分:1)

您可以自己编写类到结构的包装器:)

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);
    }
  }
}

答案 1 :(得分:1)

如果要将某些东西用作实体,则需要是类类型。我建议你应该做的是声明:

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; }
}

然后在需要封装X和Y的东西的情况下使用类型Point的变量,其中行为独立于任何其他坐标,并在需要的情况下使用MovableEntity类型的变量封装对实体的引用(这样改变一个这样的变量的X字段将改变另一个的Y)。

如图所示定义类型,访问MovableEntity的Location字段中的X和Y字段将产生与在可变Point类类型中访问此类字段的性能基本相同的性能,但是也会允许说出这样的话:

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

这将具有设置thing1的位置以匹配thing2的当前位置的效果,而不会干扰thing1或thing2的身份。如果MovableEntity直接封装了X和Y,而不是使用暴露字段结构来执行此操作,则有必要改为:

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

此外,如图所示定义的内容可以使Dictionary<Point, somethingElse>能够保护用作防止不正确变异的密钥的任何点。

请注意,我使用的是公共字段而不是属性。如果结构的整个目的是封装一组相关但独立的变量,那么自动属性会降低性能而不会带来任何实际好处。此外,与这些类型的字段相比,公开结构类型的自动属性 p>