4

我读过里希特的书中关于拳击的内容,但有一件事我不明白。
我已成功更改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
}
4

3 回答 3

3

发生这种情况是因为structs 是值类型,如原语(int,short等)。当您将其装箱时structobject它会制作一个单独工作的自身副本。这是一个简单的例子来说明这一点。

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对比struct

如果您想使用引用类型,您将不会遇到此问题,您的程序只会将引用传递给您的单个对象。如果需要引用类型,请使用classnot 。struct

internal class Point : IChangeBoxedPoint

何时使用结构

根据引用MSDN的其他问题

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

  • 它在逻辑上表示单个值,类似于原始类型(整数、双精度等)。
  • 它的实例大小小于 16 字节。
  • 它是不可变的。
  • 它不必经常装箱。

如果你不知道不可变意味着对象不能改变。因此,您实际上违反了良好的做法,将structs装箱interface以试图改变它们。

拳击IChangeBoxedPoint

您可以通过使用 a 来解决您的问题,List<IChangeBoxedPoint>但这只会将其更改为使用对您的值类型的引用,我的问题是,当您可以将您的更改struct为 a时,您为什么还要打扰class

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

进一步阅读

于 2013-04-04T07:51:28.617 回答
3

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

如果您将列表声明为,List<Point>那么您的值将在界面之间装箱/拆箱,正如其他人已经说过的那样。但是,如果您有一个接口列表,那么只有在您将它们添加到列表时才会将值装箱,从而允许您根据需要更改它们。

于 2013-04-04T08:03:52.303 回答
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]); 
于 2013-04-04T07:56:51.293 回答