C#扩展数组类型以重载运算符

6
我想创建一个扩展整数数组的类,它需要能够通过“+”运算符与另一个数组相加(每个元素相加),并通过“==”进行比较,以便在字典中用作键。我不想为我的新类实现整个IList接口,而只是将这两个运算符添加到现有的数组类中。我正在尝试做这样的事情:
class MyArray : Array<int>

但很明显它并不起作用 ;).

如果我表达不清楚,对不起,我已经搜索了几个小时的解决方案...

更新:

我尝试了这样的方法:

class Zmienne : IEquatable<Zmienne>
{
    public int[] x;
    public Zmienne(int ilosc)
    {
        x = new int[ilosc];
    }
    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        return base.Equals((Zmienne)obj);
    }
    public bool Equals(Zmienne drugie)
    {
        if (x.Length != drugie.x.Length)
            return false;
        else
        {
            for (int i = 0; i < x.Length; i++)
            {
                if (x[i] != drugie.x[i])
                    return false;
            }
        }
        return true;
    }

    public override int GetHashCode()
    {
        int hash = x[0].GetHashCode();
        for (int i = 1; i < x.Length; i++)
            hash = hash ^ x[i].GetHashCode();
        return hash;
    }

}

然后像这样使用:

Zmienne tab1 = new Zmienne(2);
Zmienne tab2 = new Zmienne(2);
tab1.x[0] = 1;
tab1.x[1] = 1;

tab2.x[0] = 1;
tab2.x[1] = 1;

if (tab1 == tab2)
    Console.WriteLine("Works!");

没有效果。不幸的是,我不擅长接口和重写方法。至于为什么我要尝试这么做,是因为我有一些方程式,像这样:
x1 + x2 = 0.45
x1 + x4 = 0.2
x2 + x4 = 0.11
还有很多类似的方程式,我需要将第一个方程式加到第二个方程式中,并搜索所有其他方程式,以找出是否有任何匹配结果的x组合。
也许我完全走错了方向?
4个回答

6

对于单一类型,封装起来相当容易,如下所示。请注意,作为键,您也希望使其不可变。如果您想使用泛型,则会更加困难(请求更多信息):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
static class Program {
    static void Main() {
        MyVector x = new MyVector(1, 2, 3), y = new MyVector(1, 2, 3),
                 z = new MyVector(4,5,6);
        Console.WriteLine(x == y); // true
        Console.WriteLine(x == z); // false
        Console.WriteLine(object.Equals(x, y)); // true
        Console.WriteLine(object.Equals(x, z)); // false
        var comparer = EqualityComparer<MyVector>.Default;
        Console.WriteLine(comparer.GetHashCode(x)); // should match y
        Console.WriteLine(comparer.GetHashCode(y)); // should match x
        Console.WriteLine(comparer.GetHashCode(z)); // *probably* different
        Console.WriteLine(comparer.Equals(x,y)); // true
        Console.WriteLine(comparer.Equals(x,z)); // false
        MyVector sum = x + z;
        Console.WriteLine(sum);
    }
}
public sealed class MyVector : IEquatable<MyVector>, IEnumerable<int> {
    private readonly int[] data;
    public int this[int index] {
        get { return data[index]; }
    }
    public MyVector(params int[] data) {
        if (data == null) throw new ArgumentNullException("data");
        this.data = (int[])data.Clone();
    }
    private int? hash;
    public override int GetHashCode() {
        if (hash == null) {
            int result = 13;
            for (int i = 0; i < data.Length; i++) {
                result = (result * 7) + data[i];
            }
            hash = result;
        }
        return hash.GetValueOrDefault();
    }
    public int Length { get { return data.Length; } }
    public IEnumerator<int> GetEnumerator() {
        for (int i = 0; i < data.Length; i++) {
            yield return data[i];
        }
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
    public override bool Equals(object obj)
    {
         return this == (obj as MyVector);
    }
    public bool Equals(MyVector obj) {
        return this == obj;
    }
    public override string ToString() {
        StringBuilder sb = new StringBuilder("[");
        if (data.Length > 0) sb.Append(data[0]);
        for (int i = 1; i < data.Length; i++) {
            sb.Append(',').Append(data[i]);
        }
        sb.Append(']');
        return sb.ToString();
    }
    public static bool operator ==(MyVector x, MyVector y) {
        if(ReferenceEquals(x,y)) return true;
        if(ReferenceEquals(x,null) || ReferenceEquals(y,null)) return false;
        if (x.hash.HasValue && y.hash.HasValue && // exploit known different hash
            x.hash.GetValueOrDefault() != y.hash.GetValueOrDefault()) return false;
        int[] xdata = x.data, ydata = y.data;
        if(xdata.Length != ydata.Length) return false;
        for(int i = 0 ; i < xdata.Length ; i++) {
            if(xdata[i] != ydata[i]) return false;
        }
        return true;        
    }
    public static bool operator != (MyVector x, MyVector y) {
        return !(x==y);
    }
    public static MyVector operator +(MyVector x, MyVector y) {
        if(x==null || y == null) throw new ArgumentNullException();
        int[] xdata = x.data, ydata = y.data;
        if(xdata.Length != ydata.Length) throw new InvalidOperationException("Length mismatch");
        int[] result = new int[xdata.Length];
        for(int i = 0 ; i < xdata.Length ; i++) {
            result[i] = xdata[i] + ydata[i];
        }
        return new MyVector(result);
    }
}

Marc,这太棒了。我对如何使用泛型和/或双精度浮点数很感兴趣。我应该发起一个新的问题吗?我想对于双精度浮点数来说,只需要改变哈希函数就可以了。谢谢。 - C Mars

5

我会尝试进行封装。谢谢! - Episodex
封装几乎总是比继承更可取,特别是当您想要扩展重要的框架类型时。还要注意,在C#中实现==并不能神奇地使类型在字典中工作(F#则不同),您必须实现IEquatable<self>或覆盖Equals(object)以及实现GetHashCode()。 - ShuggyCoUk

0

你不能直接使用List类吗?通过AddRange方法,它已经可以实现你想要的功能了。


我不确定他是否不想以这种方式表示某些大数字。 - Grzenio

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接