在C#中,我有一个简单的3D矢量类。
static void Main(string[] args)
{
Vector3D a, b;
a = new Vector3D(0, 5, 10);
b = new Vector3D(0, 0, 0);
b = a;
a.x = 10;
Console.WriteLine("vector a=" + a.ToString());
Console.WriteLine("vector b=" + b.ToString());
Console.ReadKey();
}
输出是,
向量a = 10,5,10
载体b = 10,5,10
在我将a.x更改为10之前我指定了一个。所以我期待
向量a = 10,5,10
向量b = 0,5,10
根据我的理解=运算符像指针一样分配对象的引用? 在C#中我不能超载=运算符。
我是否必须手动分配每个属性?
答案 0 :(得分:10)
是的,因为Vecor3D是类,这是完全正确的。
类是引用类型,您的b = a;
语句不会复制Vector3D实例,而是复制对实例的引用。
如果你想'克隆'实例,你可以添加IClonable接口,但这或多或少被放弃了。
<X,Y,Z>
类型的更好解决方案可能是使其成为结构。结构是值类型,b = a;
的含义会改变(朝向你想要的)。
3D点符合结构的所有条件(小,无身份)。首选方法是将其设计为不可变的。
答案 1 :(得分:3)
是的,“ =运算符会像指针一样分配对象的引用”。因此,a
和b
都会在内存中引用相同的单个对象。 (之前由b
引用的对象不再被引用,将被垃圾回收。)
有多种方法可以解决这个问题:
将Vector3D
设为struct而不是类。结构是值类型而不是引用类型,因此b = a
将<{em}}的内容复制到变量a
。
在b
课程中实施Clone
方法(之前,这意味着实施Vector3D
,但this is no longer recommended)。或者,您可以创建一个ICloneable
构造函数,将另一个向量作为参数并创建副本。
如果您无法更改Vector3D
的实施,请自行手动复制这三个值(b = new Vector3D(a.x, a.y, a.z)
)。
答案 2 :(得分:2)
是的,引用类型通过引用来协商。
如果您想拥有单独的实例,则需要 CLONE 您的实例。
创建一个Vector3D.Clone()方法,如下所示:
public Vector3D Clone()
{
return new Vector3D(this.x, this.y, this.x);
}
那么你的主要应该是这样的:
static void Main(string[] args)
{
Vector3D a, b;
a = new Vector3D(0, 5, 10);
b = new Vector3D(0, 0, 0);
b = a.Clone();
a.x = 10;
Console.WriteLine("vector a=" + a.ToString());
Console.WriteLine("vector b=" + b.ToString());
Console.ReadKey();
}
但正如其他人所说,像Vector3D这样小的东西更适合作为一个不可变的结构
答案 3 :(得分:2)
您可能希望将Vector3D
类更改为结构。这样可以使用值类型而不是引用类型。
您的另一个选择是实施ICloneable
或使用其他方法来创建对象的深层副本。
答案 4 :(得分:1)
你可以把它变成像亨克所说的结构。你可以添加一个构造函数
struct Vector3D
{
public int x;
public int y;
public int z;
public Vector3D(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}", x, y, z);
}
}
您也可以在不添加构造函数的情况下执行此操作。
b = new Vector3D() {x=0, y=0, z=0};
答案 5 :(得分:0)
无需使用struct
,我建议您将Vector3D
设计为不可变类。 Here是一些很好的例子。当然,对于不可变类,a.x = 10
是不可能的。