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