【问题标题】:c# = operator problemc# = 运算符问题
【发布时间】:2011-03-21 20:06:39
【问题描述】:

在 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。所以我期待

向量 a= 10, 5, 10

向量 b= 0, 5, 10

据我了解,= 运算符会像指针一样分配对对象的引用? 在 C# 中,我不能重载 = 运算符。

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

【问题讨论】:

  • 这里的最佳做法是创建一个 不可变 类型,无论是引用类型还是值类型,都无关紧要。向量在逻辑上是。当您将四添加到十二时,您不会在逻辑上将两者“变异”为六并保持相同!你完全创造了一个全新的数字。同样,当您更改向量的 x 坐标时,您不会更改 x 坐标并保持 y 和 z 相同:您创建了一个全新的向量。您会发现,如果您将值视为值而不是可变状态,则您能够更好地推理向量数学。

标签: c# operators


【解决方案1】:

是的,因为 Vecor3D 是一个,这是完全正确的。

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

如果您想“克隆”实例,可以添加 IClonable 接口,但这或多或少已被放弃。

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

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

【讨论】:

  • @Kayhano:如果你想让它成为一个类,是的。但是看最后一个版本,最好的办法是把它做成一个结构体。
  • @Kayhano,或者您可以将 Vector3D 类更改为结构(Henk 回答的最后一行)。
【解决方案2】:

是的,正如您所说,“= 运算符像指针一样分配对对象的引用”。因此,ab 都引用了内存中相同的 single 对象。 (b 之前引用的对象不再被引用,将被垃圾回收。)

有多种方法可以解决这个问题:

  1. Vector3D 设为 struct 而不是类。结构是类型而不是引用类型,所以b = a复制a的内容到变量b

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

  3. 如果无法更改Vector3D的实现,请自行手动复制三个值(b = new Vector3D(a.x, a.y, a.z))。

【讨论】:

    【解决方案3】:

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

    您的另一个选择是实现ICloneable 或使用其他方法来创建对象的深层副本。

    【讨论】:

    • Arent the Vector types in XNA all struct?
    • @Allen :我根本没有玩过 XNA,所以我不能告诉你。然而,我的猜测是它们是。
    【解决方案4】:

    是的,引用类型由引用分配。

    如果你想拥有一个单独的实例,你想CLONE你的实例。

    创建一个 Vector3D.Clone() 方法,如下所示:

    public Vector3D Clone()
    {
        return new Vector3D(this.x, this.y, this.x);
    }
    

    那么你的 Main 应该是这样的:

    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 这样小的东西更适合作为不可变结构

    【讨论】:

      【解决方案5】:

      你可以像 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};
      

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-23
          • 2014-04-14
          • 2021-10-01
          • 2023-04-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多