-1

我有一个描述点的结构:

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
}

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

为了清楚下面的一些代码来解释我想要做什么:

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 中的一个点,那么其他列表中的对应点将被更改。

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

那么:lst1[0].X 等于 400,lst2[0].X 等于 800;

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

我使用的解决方法是将结构更改为类。A Point 是一个引用类型,一切正常......完美。

我的问题是:将 struct 更改为 class 是唯一的解决方法吗?是否没有解决方案可以用相同结构实例的实例填充列表,从而更改列表中的点会更改共享同一实例的所有其他点?

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

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

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

提前致谢!

编辑 在这里进行编辑以回答您的一些评论。我知道(或者我想我知道)使用 struct 的好处,特别是 struct 放在堆上。因为我可以有很多积分,所以考虑到性能问题,最好使用结构。我不想使用指针,因为我不想设置不安全的上下文。我没有任何理由不使用类。尽管如此,我的问题对我的文化来说更重要,因为我很惊讶无法找到一种简单的方法来将单个结构实例存储在多个列表中。

感谢所有人

4

2 回答 2

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

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

使用如图所示定义的类型,访问 a 的 Location 字段中的 X 和 Y 字段MovableEntity将产生与访问可变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>将保护用作密钥的任何点免受不当突变的影响。

请注意,我使用了公共字段而不是属性。如果结构的全部目的是封装一组相关但独立的变量,那么自动属性将降低性能而不会提供任何真正的好处。此外,与此类类型的字段相比,公开结构类型的自动属性效率要低得多且难以使用,因此应避免使用,除非它们提供足以证明成本合理的语义优势。

于 2013-11-14T17:41:55.410 回答
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);
    }
  }
}
于 2013-11-12T13:59:09.137 回答