2010-07-27 68 views
6

在C#中,我有一个简单的3D矢量类。c#=运算符问题

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

我分配之前我改变斧至10所以我期待

向量a = 10,5,10

矢量b = 0,5,10

从我理解的=运算符分配一个对象的引用像指针? 而在C#我无法超载=运营商。

我必须手动分配每个属性吗?

+5

这里的最佳做法是使一个* immutable *类型(引用类型或值类型)无关紧要。向量是逻辑*值*。当你添加四到十二个时,你不会在逻辑上将这两个变成六个,并且保持相同!你完全创建一个全新的号码。同样,当您更改矢量的x坐标时,您不会更改x坐标并保持y和z相同:您创建一个全新的矢量。你会发现,如果将值作为值处理,而不是作为可变状态,则能更好地推理向量数学。 – 2010-07-27 22:16:57

回答

10

是的,因为Vecor3D是这是非常正确的。

类是引用类型,您的b = a;语句不会复制Vector3D实例,而是对实例的引用。

如果你想'克隆'实例,你可以添加IClonable接口,但是或多或少地放弃了。

<X,Y,Z>类型的更好的解决方案可能是使它成为一个结构。结构是值类型,b = a;的含义会改变(朝你想要的)。

一个3D点满足结构(小,无身份)的所有标准。首选的方法是将其设计为不可变的。

+0

然后我必须手动分配每个属性? – Kayhano 2010-07-27 20:44:31

+0

@Kayhano:如果你想让它成为一堂课,是的。但看到最后的版本,最好的想法是使它成为一个结构。 – 2010-07-27 20:49:24

+0

如果你使它成为一个结构,它会按照你的预期工作。 – ConsultUtah 2010-07-27 20:50:07

2

是的,引用类型是通过引用分配的。

如果你想有一个单独的实例,你想要克隆你的实例。

创建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会更适合作为不可变的结构

2

您可能希望将Vector3D类更改为结构。这可以让你使用值类型而不是引用类型。

您的其他选择是实施ICloneable或使用其他方法创建对象的深层副本。

+0

Arent XNA中的矢量类型都是'struct'吗? – 2010-07-28 20:51:14

+0

@Allen:我还没有玩过XNA,所以我不能告诉你。然而,我的猜测是,他们是。 – AllenG 2010-07-28 20:53:46

+0

是的,他们是:) http://msdn.microsoft.com/en-us/library/bb196942(v=XNAGameStudio.40).aspx – 2010-07-29 14:35:20

3

是的,“=运算符分配一个对象的引用,如指针”,就像你说的那样。因此,ab均参考存储器中的相同对象单一。(以前b引用的对象没有被引用的任何更多的,将是垃圾收集。)

有多种方式来解决这个问题:

  1. Vector3D一个struct,而不是一类。结构类型,而不是参考类型,所以b = a副本a的内容为变量b

  2. Vector3D类实现一个Clone方法(以前,这将意味着实施ICloneable,但this is no longer recommended)。或者,您可以创建一个将另一个向量作为参数并创建副本的构造函数。

  3. 如果您无法更改Vector3D的实施方式,请亲自手动复制这三个值(b = new Vector3D(a.x, a.y, a.z))。

1

你可以使它像一个像Henk说的结构。您可以添加构造函数

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

无需使用struct,我建议你应该设计自己的Vector3D作为不变类。 Here就是一些很好的例子。当然,a.x = 10将不可能为一个不可变的类。