how to use where for operators at generics class c#? [duplicate]
Asked Answered
M

4

6

Hi I would like to have a class:

class Matrix <T>
    where T : // I don't know what to write here
{
    T[][] elements;
}

I would like T to be addable and multiplyable by + and * operators

Madelynmademoiselle answered 7/2, 2013 at 18:57 Comment(3)
Unfortunately, there is no constraint for types that implement specific operators. There are workarounds that I wouldn't personally use, such as casting to dynamic.Owe
Constraint for only integers with a possible solution being IConvertibleSurefooted
although an interesting question, would it work by implicitly specifying the types (such as iMatrix for int and fMatrix for float)?Geo
C
2

I would highly recommend you take a look at the "MiscUtil" library from Messrs Skeet and Gravell:

http://www.yoda.arachsys.com/csharp/miscutil/

Contained within is an incredible "generic math operators" implementation, which should line up nicely with your attempts to create a generic matrix math class. It actually reminds me (a bit) of python and how it handles referencing the operator functions directly.

(aside to @jon-skeet : any chance of this making its way to Nuget?)

Some example usages from their tests:

double sumOperator = 0;
for (int i = 0; i < COUNT; i++)
{
    sumOperator = Operator.Add(sumOperator, rand.NextDouble());
}

int sumOperator = 0;
for (int i = 0; i < COUNT; i++)
{
    sumOperator = Operator.Add(sumOperator, rand.Next(MAXVALUE));
}
Crete answered 7/2, 2013 at 19:45 Comment(0)
S
2

This is not possible because the unconstrained generic type is assumed to be of type Object, which doesn't define the arithmetic operators. Hence, it seems you need to specify an interface.

But, the primitive types (Int32, Double, etc) define the arithmetic operations effectively as static methods (actually the compiler treats them specially and generates the code inline) and an interface in C# cannot define static methods (although the design of the CLR actually allows it). Hence, no interface be written in C# which satisfies the requirements of supporting the arithmetic operations; even if it could be written, the primitive types don't inherit it, so it still wouldn't work.

The end result is that there's no way to do what you want in C#.

If you do try it, you get an error similar to

Operator '+' cannot be applied to operands of type 'T' and 'T'

If you do a web search for this message, you'll find various discussions about possible workarounds.

Sorrel answered 7/2, 2013 at 19:54 Comment(0)
D
1

As I'm not aware of any built-in solution, check this out:

public abstract class BaseClass
{
    public static BaseClass operator +(BaseClass p1, BaseClass p2)
    {
        return p1 + p2;
    }

    public static BaseClass operator *(BaseClass p1, BaseClass p2)
    {
        return p1 * p2;
    }
}

public class ChildClass : BaseClass
{
}

public class Matrix <T> where T : BaseClass
{
    T[][] elements;
}

Hope this helps.

However, other types, such as int, won't be supported.

Distinctly answered 7/2, 2013 at 19:10 Comment(2)
if there's another class that supports + and * but doesn't inherit BaseClass this will not work. For instance intGeo
@Default Indeed, thanks for pointing this out. I've updated the answer to add this restriction.Distinctly
M
1

May be this way will be helpful for someone. You can improve this by put add, multiplicate functions in fabric-library class.

UPDATE May be putting Operators from JerKimball post into counstructor

class Matrix <T>
{
    T[][] elements;

    public Matrix(Func<T, T, T> add, Func<T,T,T> multiplicate)
    {
        this.Add = add;
        this.Mult = multiplicate;
    }

    public Matrix<T> operator +(Matrix<T> p1, Matrix<T> p2)
    {
        // correct this
        var t = Add(p1.elements[0][0], p2.elements[0][0]);
        return this;
    }

    public Matrix<T> operator *(Matrix<T> p1, Matrix<T> p2)
    {
        // correct this
        var t = Mult(p1.elements[0][0], p2.elements[0][0]);
        return this;
    }

    private Func<T, T, T> Add { get; set; }

    private Func<T, T, T> Mult { get; set; }
}

static void Main(string[] args)
{
    var m1 = new Matrix<int>((x,y) => x + y, (x,y) => x * y);
    var m2 = new Matrix<int>((x, y) => x + y, (x, y) => x * y);
}

UPDATE 2

just provide access to property like this:

    public T[][] Elements { get; set; }

and you can do this:

m1.Elements[0][0] = 10;
var m3 = new Matrix<int?>((x, y) => x + y, (x, y) => x * y);
m3.Elements[0][0] = null;
Murton answered 7/2, 2013 at 19:32 Comment(2)
this way i cant give value to element (like 0 or any number, also cant cast them to int or any non nullable type)Gilmer
Could you provide an example what you can not do?Murton

© 2022 - 2024 — McMap. All rights reserved.