C#为什么我的运算符重载使对象变异而不是返回新的对象?

时间:2018-07-20 09:45:22

标签: c# methods operator-overloading

我正在研究矩阵/向量类,其中一部分具有运算符重载。奇怪的事情之一是,不是返回一个新的对象(在本例中为vector),而是对该向量进行了变异,并返回了一个新的对象。如何干净地返回Vector的新实例?

这是构造函数:

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

和运算符重载(仅发布加法,因为它们全部都有问题,并且结构相似,因此应该有相同的解决方案)

    public static Vector operator + (Vector a, Vector b)
    {
        Vector c = new Vector();
        c = a;
        for (int dim = 0; dim < c.dims; dim++)
        {
            c[dim] += b[dim];
        }
        return c;
    }

编辑:因此,我将类更改为结构,似乎仍然有问题。也许是因为变量v是一个列表,因此它是一个类,仍在传递对列表的引用吗?也许我必须使用数组而不是列表?

5 个答案:

答案 0 :(得分:3)

该行:

c = a;

是问题。

然后ca都指向同一个对象。

可能的解决方案:

1)将Vector从类更改为结构。

2)使用您的构造函数之一创建一个新的Vector对象:

公共静态矢量运算符+(矢量a,矢量b)

{
    Vector c = new Vector(a.v);

    for (int dim = 0; dim < c.dims; dim++)
    {
        c[dim] += b[dim];
    }
    return c;
}

答案 1 :(得分:3)

问题是您的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;
}

小加号:您可以将您的dims成员更改为只读属性:

private int dims { get { return v.Count; } }

如何测试:

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

结果:

>c = a + b
>1.42857 + 1.42857 = 2.85714
>1.42857 + 2.85714 = 4.28571
>1.42857 + 4.28571 = 5.71428

答案 2 :(得分:1)

您应该将所有向量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;
}

答案 3 :(得分:0)

您可以使用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);
    }
}

答案 4 :(得分:0)

好的,我已经完成了一些工作。这有点杂乱,但是可以用。而且我不知道为什么我必须跳很多圈才能使此功能正常工作,但这是我的解决方案:

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

我不确定是否有更优雅的方法来做到这一点,但是,嘿,它可行。我也将它设为结构而不是类。