C# Generic Operators

C# Generic Operators

No, you can't declare generic operators in C#.

Operators and inheritance don't really mix well.

If you want Foo + Foo to return a Foo and Bar + Bar to return a Bar, you will need to define one operator on each class. But, since operators are static, you won't get the benefits of polymorphism because which operator to call will be decided at compile-time:

Foo x = new Bar();
Foo y = new Bar();
var z = x + y; // calls Foo.operator+;

Is there a generic constraint I could use for the + operator?

There are no such devices in C#. A few options are available, though:

  • in C# 4.0 and .NET 4.0 (or above), use dynamic, which supports + but offers no compile time checking
  • in .NET 3.5 (or above), MiscUtil offers an Operator class which makes operators available as methods - again, without any compile-time checking

So either:

return (dynamic)left.Evaluate(context) + (dynamic)right.Evaluate(context);

or

return Operator.Add(left.Evaluate(context), right.Evaluate(context));

Support of + operator in a generic class in C#

Because the type of T is not known until instantiation, there is no guarantee that the type T will support the + operator.

There's a workaround using dynamic operator: (note: if you don't pass + supported operands then it WILL throw a runtime error.)

public T totalNums(T num1, T num1)
{
dynamic dx = num1, dy = num1;
return dx + dy;
}

Can't operator == be applied to generic types in C#?

"...by default == behaves as described above for both predefined and user-defined reference types."

Type T is not necessarily a reference type, so the compiler can't make that assumption.

However, this will compile because it is more explicit:

    bool Compare<T>(T x, T y) where T : class
{
return x == y;
}

Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"

I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.

namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();

Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);

}

static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}

class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}

public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}

Output

Inline:
Overloaded == called

Generic:

Press any key to continue . . .

Follow Up 2

I do want to point out that changing my compare method to

    static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}

causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.

Define a generic that implements the + operator

This is a pretty commonly requested new feature for C#: the ability to specify more generic parameter constraints than the ones we already have. Operators are among the most frequently asked. However, C# does not currently support this.

Possible workarounds:

  • Pass a delegate to any method that needs to do addition. This is the most type-safe option, but of course it’s annoying if you need to call such a method often. For example:

    public class Generic<T> {
    public void DoSomething(T anItem, T anotherItem, Func<T, T, T> add) {
    // instead of
    Blah(anItem + anotherItem);
    // have to write:
    Blah(add(anItem, anotherItem));
    }
    }

    Generic<int> genInt = ...;
    // and then instead of ...
    genInt.DoSomething(1, 2);
    // have to write:
    genInt.DoSomething(1, 2, (a, b) => a + b);
  • Declare your own interface IAddable. Then you can use it as a generic type parameter constraint, but obviously you can’t use int as the parameter then. You would have to use a struct of your own that contains just an int and which implements IAddable:

    public interface IAddable<T> {
    T Add(T other);
    }
     
    public struct Integer : IAddable<Integer> {
    public int Value;
    public Integer(int value) { Value = value; }
    public Integer Add(Integer other) { return new Integer(Value + other.Value); }
    }

    // then instead of
    Generic<int> blah = ...;
    // have to write:
    Generic<Integer> blah = ...;
  • dynamic. Another possible workaround is to use dynamic, but this is rather hacky and completely unsafe: it will let you pass in any type and call any method or operator, and only crash at runtime, not at compile-time.

Operator as and generic classes

You need to add

where T : class

to your method declaration, e.g.

T Execute<T>()  where T : class
{

By the way, as a suggestion, that generic wrapper doesn't really add much value. The caller can write:

MyClass c = whatever.Execute() as MyClass;

Or if they want to throw on fail:

MyClass c = (MyClass)whatever.Execute();

The generic wrapper method looks like this:

MyClass c = whatever.Execute<MyClass>();

All three versions have to specify exactly the same three entities, just in different orders, so none are any simpler or any more convenient, and yet the generic version hides what is happening, whereas the "raw" versions each make it clear whether there will be a throw or a null.

(This may be irrelevant to you if your example is simplified from your actual code).

Valid approach for generic operators

(expanding from the comments) A generic class doesn't seem to be necessary. A valid approach for getting operators to work for generic types is to re-work the types so that they're no longer generic.

ColorSet could be defined as

public class ColorSet {
private Color red;
private Color green;
private Color blue;

protected ColorSet(Type type) {
red = (Color)Activator.CreateType(type);
red.Name = Values.Res.get("red");
green = (Color)Activator.CreateType(type);
green.Name = Values.Res.get("red");
blue = (Color)Activator.CreateType(type);
blue.Name = Values.Res.get("red");
}

public static ColorSet FromType<T>() where T : Color {
return new ColorSet(typeof(T));
}
}

Instead of new ColorSet<ExtendedColor>(), you would now call ColorSet.FromType<ExtendedColor>().

This works so long as you don't actually need to use your T outside of your constructor.

If you had, for instance, a

public T Red { get { return red; } }

property, you would need to change that to a

public Color Red { get { return red; } }

property.

However, if you have anything like that, and you do want to keep the generic type, you can then put that in a derived generic class:

public class ColorSet<T> : ColorSet where T : Color {
public ColorSet<T>() : base(typeof(T)) { }
public new T Red { get { return (T)base.Red; } }
}

which still only needs operators for the base non-generic ColorSet class.

operator overloading with generics

The problem is the compiler cannot know if + operator can be applied to T. Unfortunately, there is no way to constraint T to be a numeric type in C#.

However, you might be able to workaround this using the dynamic runtime:

public class Complex<T> where T : struct
{
public T _a, _b;
public Complex(T i, T j)
{
_a = i;
_b = j;
}
public static Complex<T> operator +(Complex<T> i, Complex<T> j)
{
return new Complex<T>(Sum(i._a, j._a), Sum(i._b, j._b));
}

private static T Sum(T a, T b)
{
return (dynamic)a + (dynamic)b;
}
}

Implementing arithmetic in generics?

Unfortunately you cannot use arithmetic operations on generic types

T Add(T a, T b)
{
return a + b; // compiler error here
}

will not work in c#!

But you can create your own numeric types and overload the operators (arithmetic, equality and implicit, explicit). This lets you work with them in a quite natural way. However you cannot create an inheritance hierarchy with generics. You will have to use a non generic base class or interface.

I just did it with a vector type. A shortened version here:

public class Vector
{
private const double Eps = 1e-7;

public Vector(double x, double y)
{
_x = x;
_y = y;
}

private double _x;
public double X
{
get { return _x; }
}

private double _y;
public double Y
{
get { return _y; }
}

public static Vector operator +(Vector a, Vector b)
{
return new Vector(a._x + b._x, a._y + b._y);
}

public static Vector operator *(double d, Vector v)
{
return new Vector(d * v._x, d * v._y);
}

public static bool operator ==(Vector a, Vector b)
{
if (ReferenceEquals(a, null)) {
return ReferenceEquals(b, null);
}
if (ReferenceEquals(b, null)) {
return false;
}
return Math.Abs(a._x - b._x) < Eps && Math.Abs(a._y - b._y) < Eps;
}

public static bool operator !=(Vector a, Vector b)
{
return !(a == b);
}

public static implicit operator Vector(double[] point)
{
return new Vector(point[0], point[1]);
}

public static implicit operator Vector(PointF point)
{
return new Vector(point.X, point.Y);
}

public override int GetHashCode()
{
return _x.GetHashCode() ^ _y.GetHashCode();
}

public override bool Equals(object obj)
{
var other = obj as Vector;
return other != null && Math.Abs(other._x - _x) < Eps && Math.Abs(other._y - _y) < Eps;
}

public override string ToString()
{
return String.Format("Vector({0:0.0000}, {1:0.0000})", _x, _y);
}
}


Related Topics



Leave a reply



Submit