更改集合中的结构

时间:2013-04-04 07:48:29

标签: c# .net

我在里希特的书中读过有关拳击的内容,有一点我不明白 我已成功更改了对象中的struct。但是当我尝试在集合中更改struct时,我遇到了问题。

//my struct
internal struct Point:IChangeBoxedPoint
{
    public Int32 x, y;
    public void Change(Int32 x, Int32 y)
    {
        this.x = x;
        this.y = y;
    }

    public override string ToString()
    {
        return String.Format("{0}, {1}", this.x, this.y);
    }
}

public static void Main()
{
    List<Point> a = new List<Point>();
    Point p = new Point();
    p.Change(1, 1);
    Console.WriteLine(p); //write 1, 1
    object o = p;
    Console.WriteLine(o); //write 1, 1
    ((Point)o).Change(2, 2);
    Console.WriteLine(o); //write 1, 1
    ((IChangeBoxedPoint)o).Change(3, 3);
    Console.WriteLine(o); //write 3, 3
    for (int i = 0; i < 10; i++)
    {
        p.x = p.y = i;
        a.Add(p);
    }

    Console.WriteLine(a[0]); //write 0, 0
    ((IChangeBoxedPoint)a[0]).Change(300,300);
    Console.WriteLine(a[0]); //still writes 0,0
}

3 个答案:

答案 0 :(得分:3)

这种情况正在发生,因为struct是值类型,如基元(intshort等)。当您在struct中装object时,它会自行复制一份单独的作品。这是一个简单的例子来说明这一点。

Point a = new Point();
Console.WriteLine(a); // 0, 0
a.Change(1, 1);
Console.WriteLine(a); // 1, 1
object b = a;
Console.WriteLine(b); // 1, 1
a.Change(2, 2);
Console.WriteLine(a); // 2, 2
Console.WriteLine(b); // 1, 1

class vs struct

如果你想使用引用类型,你将不会遇到这个问题,你的程序只会传递对你的单个对象的引用。如果您想要参考类型,请使用class而不是struct

internal class Point : IChangeBoxedPoint

何时使用结构

根据引用this other questionMSDN

  

除非类型具有以下所有特征,否则不要定义结构:

     
      
  • 它逻辑上表示单个值,类似于基本类型(整数,双精度等)。
  •   
  • 实例大小小于16个字节。
  •   
  • 这是不可改变的。
  •   
  • 不必频繁装箱。
  •   

如果你不知道不可变意味着对象无法改变。所以你实际上是通过在struct中装interface来试图改变它们来反对良好做法。

拳击IChangeBoxedPoint

您可以使用List<IChangeBoxedPoint>来解决您的问题,但这只是将其更改为使用对您的值类型的引用,我的问题是为什么您只需更改struct时就会烦恼到class

List<IChangeBoxedPoint> a = new List<IChangeBoxedPoint>();

进一步阅读

答案 1 :(得分:3)

您应该将您的收藏集声明为List<IChangeBoxedPoint>而不是List<Point>

如果您将列表声明为List<Point>,那么您的值将被打包/取消装入接口,就像其他人已经说过的那样。但是如果你有一个接口列表,那么只有当你将它们添加到列表中时,才会将值装箱,允许你根据需要更改它们。

答案 2 :(得分:0)

似乎是对的:

Console.WriteLine(a[0]); //write 0, 0 -

仅因为您的第一件商品已收到i=0

对于此代码,

 ((IChangeBoxedPoint)a[0]).Change(300,300);

实际上并没有改变第一项。 它创建了盒装对象Point的新实例,并更改了其值。

尝试将其更改为

 Point newPoint = new Point();
 newPoint.Change(300,300);
 a[0] = newPoint;
 Console.WriteLine(a[0]);