Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Extend array type to overload operators

I'd like to create my own class extending array of ints. Is that possible? What I need is array of ints that can be added by "+" operator to another array (each element added to each), and compared by "==", so it could (hopefully) be used as a key in dictionary.

The thing is I don't want to implement whole IList interface to my new class, but only add those two operators to existing array class.

I'm trying to do something like this:

class MyArray : Array<int>

But it's not working that way obviously ;).

Sorry if I'm unclear but I'm searching solution for hours now...

UPDATE:

I tried something like this:

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

}

Then use it like this:

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!");

And no effect. I'm not good with interfaces and overriding methods unfortunately :(. As for reason I'm trying to do it. I have some equations like:

x1 + x2 = 0.45
x1 + x4 = 0.2
x2 + x4 = 0.11

There are a lot more of them, and I need to for example add first equation to second and search all others to find out if there is any that matches the combination of x'es resulting in that adding.

Maybe I'm going in totally wrong direction?

like image 219
Episodex Avatar asked Nov 26 '09 16:11

Episodex


1 Answers

For a single type, it is pretty easy to encapsulate, as below. Note that as a key you want to make it immutable too. If you want to use generics, it gets harder (ask for more info):

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);
    }
}
like image 85
Marc Gravell Avatar answered Sep 29 '22 00:09

Marc Gravell