Home > Mobile >  Is this possible? Specify any generic type as long as the operation is defined on it
Is this possible? Specify any generic type as long as the operation is defined on it

Time:11-21

I'm not sure if this is possible, but if it is then it would be useful.

I am attempting to program in a class called Matrix<T>. The intent is to be able to have matrices of various data types, such as integers, floats, doubles, etc.

I now want to define addition:

    public static Matrix<T> operator  (Matrix<T> first, Matrix<T> second)
    {
        if (first.dimension != second.dimension)
        {
            throw new Exception("The matrices' dimensions do not match");
        }
        Matrix<T> add = new Matrix<T>(first.dimension);

        for (int i = 1; i <= first.rows; i  )
        {
            for (int j = 1; j <= first.columns; i  )
            {
                add[i,j] = first[i,j]   second[i,j];
            }
        }
        return add;
    }

There is an issue with the line add[i,j] = first[i,j] second[i,j]; since the operation is not defined on a general object of type T.

I only want to specify matrices where T is a type such that addition is defined, however. So, I can make a matrix of ints, floats, doubles, etc. but if I were to try and define a matrix of, say, int[]s, I would want this to throw an exception since is not defined for int[]s.

So, instead of writing T, is there some way of telling the computer "this can take in any generic type, as long as an operator is defined on the type? Or, is this not possible and I would have to sepeately define a matrix of ints, matrix of floats, and so on?

Edit: I don't see how the linked question from closure is related to this - I see nothing about operators there. If they are related, can somebody explain how?

CodePudding user response:

Currently it is not possible (at least without losing compile time safety or changing the API) but with preview features enabled and System.Runtime.Experimental nuget you can use IAdditionOperators to restrict T to have operator defined. I would say that adding this interface also to Matrix itself can be a good idea:

class Matrix<T> : IAdditionOperators<Matrix<T>, Matrix<T>, Matrix<T>> where T : IAdditionOperators<T, T, T>
{
   public static Matrix<T> operator  (Matrix<T> left, Matrix<T> right)
    {
        // swap to real implementation here
        T x = default;
        T y = default;
        Console.WriteLine(x   y);
        return default;
    }
}

See also:

CodePudding user response:

It's possible using reflection

class Int
{
    readonly int v;

    public int Get => v;

    public Int(int v)
    {
        this.v = v;
    }

    public static Int operator  (Int me, Int other) => new Int(me.v   other.v);
}


class Arr<T>
{
    T[] _arr;

    public Arr(T[] arr)
    {
        _arr = arr;
    }

    public T this[int index] => _arr[index];

    public static Arr<T> operator (Arr<T> me, Arr<T> other)
    {
        var addMethod = typeof(T).GetMethod("op_Addition");
        if (addMethod == null)
            throw new InvalidOperationException($"Type {typeof(T)} doesn't implement ' ' operator");
        var result = me._arr.Zip(other._arr)
            .Select(elements => addMethod.Invoke(null, new object[] { elements.First, elements.Second }))
            .Cast<T>()
            .ToArray();
        return new Arr<T>(result);
    }
}

[Test]
public void TestAdd()
{
    var firstArray = new Arr<Int>(new[] { new Int(1), new Int(2) });
    var secondArray = new Arr<Int>(new[] { new Int(2), new Int(3) });
    var sum = firstArray   secondArray;
    Assert.AreEqual(3, sum[0].Get);
    Assert.AreEqual(5, sum[1].Get);
}

Reduced the example to array. Unfortunetly it compiles even if T doesn't implement add operator, so you will get a exception in runtime. You could also check if the add method has proper signature (returns T and takes two T's). If you need help understanding the code, let me know!

  • Related