1

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?

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Robin
  • 373
  • 1
  • 3
  • 20
  • 1
    I think, generic math may help here (https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/), but this is only in preview for now. For a ordinal C# generics there is no way to achieve this. – Serg Nov 20 '21 at 21:09
  • 1
    It would me nice if there was an INumeric (or something like that) to use a constraint. But as far as I know, there isn't. We finally got a `System.Enum` constraint, we can hope – Flydog57 Nov 20 '21 at 21:10
  • 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? – Robin Nov 20 '21 at 21:15
  • With preview feature enabled you can use [`IAdditionOperators`](https://github.com/dotnet/runtime/blob/af4efb1936b407ca5f4576e81484cf5687b79a26/src/libraries/System.Private.CoreLib/src/System/IAdditionOperators.cs#L17) – Guru Stron Nov 20 '21 at 21:15
  • @Serg, Guru Stron that does look like what I need - thank you. I haven't used preview features before but I will investigate this. – Robin Nov 20 '21 at 21:18

2 Answers2

2

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:

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
1

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!

Tobraef
  • 31
  • 3