C#为什么我的操作符重载会改变对象而不是返回新对象?
我正在处理一个矩阵/向量类,其中一部分有操作符重载。奇怪的是,它不是返回一个新对象(在本例中是向量),而是对向量进行变异,然后返回一个新对象。如何干净地返回向量的新实例 以下是施工人员:C#为什么我的操作符重载会改变对象而不是返回新对象?,c#,methods,operator-overloading,C#,Methods,Operator Overloading,我正在处理一个矩阵/向量类,其中一部分有操作符重载。奇怪的是,它不是返回一个新对象(在本例中是向量),而是对向量进行变异,然后返回一个新对象。如何干净地返回向量的新实例 以下是施工人员: private List<double> v = new List<double>(); private int dims; public Vector(double[] a) { foreach (double d in a)
private List<double> v = new List<double>();
private int dims;
public Vector(double[] a)
{
foreach (double d in a)
{
v.Add(d);
dims++;
}
}
public Vector(int dims)
{
var a = new double[dims];
v = a.ToList();
this.dims = dims;
}
private Vector(List<double> a)
{
v = a;
dims = a.Count;
}
private List v=new List();
私有内部dims;
公共向量(双[]a)
{
foreach(a中的双d)
{
v、 加(d);
dims++;
}
}
公共向量(整数dims)
{
var a=新的双精度[dims];
v=a.ToList();
this.dims=dims;
}
专用向量机(列表a)
{
v=a;
dims=a.计数;
}
运算符重载(只需发布加法,因为它们都有问题,并且具有相似的结构,因此应该有相同的解决方案)
公共静态向量运算符+(向量a、向量b)
{
向量c=新向量();
c=a;
对于(int dim=0;dim
编辑:所以,我已经将类更改为struct,似乎我仍然存在这个问题。可能是因为变量v
是一个列表,因此它是一个类,它仍然在传递对列表的引用?也许我必须使用数组而不是列表?行:
c = a;
这就是问题所在
然后c
和a
都指向同一个对象
可能的解决方案:
1) 将向量从类更改为结构
2) 使用其中一个构造函数创建新的向量对象:
公共静态向量运算符+(向量a、向量b)
{
向量c=新向量(a.v);
对于(int dim=0;dim
问题在于您的c=a
会“复制”地址而不是值。您的+
运算符应如下所示:
public static Vector operator + (Vector a, Vector b)
{
if (a.dims != b.dims)
throw new WhatEverException();
Vector c = new Vector(a.dims);
// c = a
for (int dim = 0; dim < c.dims; dim++)
{
// c[dim] += b[dim];
c[dim] = a[dim] + b[dim];
}
return c;
}
如何测试:
public class Vector
{
public char Id { get; set; } // just for debug
public double this[int i] { get { return Values[i]; } set { Values[i] = value; } }
private List<double> Values { get; set; }
public int Dim { get { return Values.Count; } }
public Vector(double[] values) { Values = values.ToList(); }
public Vector(int dims) { Values = new double[dims].ToList(); }
// note this constructor, the one you posted actually copy the whole list object
public Vector(List<double> values) { Values = new List<double>(values); }
public static Vector operator +(Vector a, Vector b)
{
if (a.Dim != b.Dim)
throw new Exception();
Vector c = new Vector(a.Dim) { Id = 'c' };
for (int i = 0 ; i < c.Dim ; i++)
c[i] = a[i] + b[i];
return c;
}
}
static void Main(string[] args)
{
Vector a = new Vector(new double[] { 1.42857, 1.42857, 1.42857 }) { Id = 'a' };
Vector b = new Vector(new double[] { 1.42857, 2.85714, 4.28571 }) { Id = 'b' };
Vector c = a + b;
Console.WriteLine(string.Format(">{0} = {1} + {2}", c.Id, a.Id, b.Id));
Console.WriteLine(string.Format(">{1} + {2} = {0}", c[0], a[0], b[0]));
Console.WriteLine(string.Format(">{1} + {2} = {0}", c[1], a[1], b[1]));
Console.WriteLine(string.Format(">{1} + {2} = {0}", c[2], a[2], b[2]));
Console.ReadKey();
}
您应该将所有向量
a
值复制到向量c
,或者将vector
更改为struct而不是class
执行a=c
,使c
引用a
,因此对c
的所有修改也应用于a
。之所以发生这种情况,是因为Vector
是一个类,它作为引用而不是值传递
解决这个问题的一种方法是循环所有a
值,并将它们添加到c
。或者,更好的是,您有一个构造函数,它可以为您实现这一点,所以您的终端操作符重写应该如下所示
public static Vector operator + (Vector a, Vector b)
{
// Will work, because you are still inside Vector class and you can access all private members.
Vector c = new Vector(a.v);
for (int dim = 0; dim < c.dims; dim++)
c[dim] += b[dim];
return c;
}
公共静态向量运算符+(向量a、向量b)
{
//将起作用,因为您仍然在Vector类中,并且可以访问所有私有成员。
向量c=新向量(a.v);
对于(int dim=0;dim
您可以使用Zip
添加两个列表的元素。此外,还可以使用AddRange
代替循环
class Vector
{
private List<double> v = new List<double>();
private int dims;
public Vector(double[] a)
{
v.AddRange(a);
}
public Vector(int dims)
{
var a = new double[dims];
v = a.ToList();
this.dims = dims;
}
private Vector(List<double> a)
{
v = new List<double>(a);
dims = a.Count;
}
public static Vector operator +(Vector a, Vector b)
{
var ls = a.v.Zip(b.v, (x, y) => x + y).ToList();
return new Vector(ls);
}
}
类向量
{
私有列表v=新列表();
私有内部dims;
公共向量(双[]a)
{
v、 AddRange(a);
}
公共向量(整数dims)
{
var a=新的双精度[dims];
v=a.ToList();
this.dims=dims;
}
专用向量机(列表a)
{
v=新列表(a);
dims=a.计数;
}
公共静态向量运算符+(向量a、向量b)
{
var ls=a.v.Zip(b.v,(x,y)=>x+y).ToList();
返回新向量(ls);
}
}
好吧,我终于想出了办法。虽然有点凌乱,但效果不错。我不知道为什么我必须跳过这么多的障碍才能让这件事顺利进行,但我的解决方案是:
public static Vec operator + (Vec a, Vec b)
{
Vec c = new Vec();
c.v = new List<double>();
for (int dim = 0; dim < a.Dims; dim++)
{
c.v.Add(a[dim] + b[dim]);
}
return c;
}
公共静态向量运算符+(向量a、向量b)
{
Vec c=新的Vec();
c、 v=新列表();
对于(int dim=0;dim
我不确定是否有一个更优雅的方式来做到这一点,但嘿,它的工作。我还把它变成了一个结构而不是一个类。如何解决这个问题?@HimBromBeere如果没有更多关于操作符要实现什么以及操作约束的信息,就有点难说了。如果
a
和b
具有不同的长度,会发生什么?例如,向量可以转换为结构吗?那么这是一个注释,而不是对“如何干净地返回向量的新实例”问题的回答@MatthewWatson这是一个名为Vector的自定义类,问题明确地说它是一个类。结构是在赋值时复制的。我建议你重命名你的类以避免混淆。我可能应该,旧的名称是Vec,我应该再次使用它。将dims更改为只读会阻止我在声明中正确设置吗?因为我现在把Vector类设置为一个可索引类,如果我将其设置为ReadOnly,我不确定Add()方法是否能正常运行。我实际上已经尝试在函数中构造c,但它仍然引用Vector a,我将尝试将其重新编写为一个结构,看看是否有效。只读属性类似于单个方法。您根本不需要设置属性,因为它会自动计算!我会做一些尝试,但我不明白它如何仍然可以引用a
,因为我们从不使用它,只使用它的值。我已经用您想要/需要的完整代码进行了编辑。这对我来说没有问题,我甚至添加了一个“Id”属性来检查我得到的实例。好的,这些都是非常酷的快捷方式,我一定会记住它们。
>c = a + b
>1.42857 + 1.42857 = 2.85714
>1.42857 + 2.85714 = 4.28571
>1.42857 + 4.28571 = 5.71428
public static Vector operator + (Vector a, Vector b)
{
// Will work, because you are still inside Vector class and you can access all private members.
Vector c = new Vector(a.v);
for (int dim = 0; dim < c.dims; dim++)
c[dim] += b[dim];
return c;
}
class Vector
{
private List<double> v = new List<double>();
private int dims;
public Vector(double[] a)
{
v.AddRange(a);
}
public Vector(int dims)
{
var a = new double[dims];
v = a.ToList();
this.dims = dims;
}
private Vector(List<double> a)
{
v = new List<double>(a);
dims = a.Count;
}
public static Vector operator +(Vector a, Vector b)
{
var ls = a.v.Zip(b.v, (x, y) => x + y).ToList();
return new Vector(ls);
}
}
public static Vec operator + (Vec a, Vec b)
{
Vec c = new Vec();
c.v = new List<double>();
for (int dim = 0; dim < a.Dims; dim++)
{
c.v.Add(a[dim] + b[dim]);
}
return c;
}