6

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?

4 Answers 4

6

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);
    }
}
1
  • Marc, this is great. I would be interested in how to do this with generics and/or doubles. Should I start a new question? I imagine for doubles is it just a case of changing the hash function. Thanks.
    – C Mars
    Commented Apr 23, 2014 at 9:22
5

Its not permitted to extend the array class, see the reference: http://msdn.microsoft.com/en-us/library/system.array.aspx

You could either implement IList (which has the basic methods), or encapsulate an Array in your class and provide conversion operators.

Please let me know if you need more detail.

2
  • I'll try encapsulating then. Thanks!
    – Episodex
    Commented Nov 26, 2009 at 16:43
  • encapsulation is almost always preferable to inheritance, especially when you want to extend a significant framework type. Note also that implementing == does NOT magically make a type work in a dictionary in c# (f# is a different matter) you must implement either IEquatable<self> or overrode Equals(object) as well as implementing GetHashCode()
    – ShuggyCoUk
    Commented Nov 26, 2009 at 17:26
0

Can you not just use the List class? This already does what you want via the AddRange method.

1
  • I am not sure if he doesn't want to represent some big numbers this way.
    – Grzenio
    Commented Nov 26, 2009 at 16:47
0

implement the ienumerable interface

Not the answer you're looking for? Browse other questions tagged or ask your own question.