我在里希特的书中读过有关拳击的内容,有一点我不明白
我已成功更改了对象中的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
}
答案 0 :(得分:3)
这种情况正在发生,因为struct
是值类型,如基元(int
,short
等)。当您在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 question的MSDN。
除非类型具有以下所有特征,否则不要定义结构:
- 它逻辑上表示单个值,类似于基本类型(整数,双精度等)。
- 实例大小小于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]);