Arithmetic Operator Overloading for a Generic Class in C#

Arithmetic operator overloading for a generic class in C#

I think the best you'd be able to do is use IConvertible as a constraint and do something like:

 public static operator T +(T x, T y)
where T: IConvertible
{
var type = typeof(T);
if (type == typeof(String) ||
type == typeof(DateTime)) throw new ArgumentException(String.Format("The type {0} is not supported", type.FullName), "T");

try { return (T)(Object)(x.ToDouble(NumberFormatInfo.CurrentInfo) + y.ToDouble(NumberFormatInfo.CurrentInfo)); }
catch(Exception ex) { throw new ApplicationException("The operation failed.", ex); }
}

That won't stop someone from passing in a String or DateTime though, so you might want to do some manual checking - but IConvertible should get you close enough, and allow you to do the operation.

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;
}
}

C# create operator overload for concrete type of generic class or struct

You can write an extension method -- this is what the runtime does for e.g. Vector128<T>. This does mean you need a method rather than an operator however.

public static class CRangeExtensions
{
public static CRange<double> Multiply(this CRange<double> range, double factor)
{
return new CRange(range.LowerBound * factor, range.UpperBound * factor);
}

// Same for int...
}

If you're OK using preview features, you can make use of Generic math which defines the INumber<T> interface:

public readonly struct CRange<T> where T : INumber<T>
{
public T LowerValue { get; }
public T UpperValue { get; }

public CRange(T lower, T upper) => (LowerValue, UpperValue) = (lower, upper);

public static CRange<T> operator * (CRange<T> range, T factor)
{
return new CRange<T>(range.LowerValue * factor, range.UpperValue * factor);
}
}

SharpLab.

Operators in C# Generics

how we can do it(use operators in Generic Methods)

Generally, we can't. For most operators, if used with a type parameter (say T), the compiler cannot work out an applicable overload to use at compile-time.

If you write user-defined operators on a base class (that is on a reference type that is non-sealed), you can use them if you have a constraint. For example System.Uri is a non-sealed class that overloads the == operator. Then if you do:

class Test<T> where T : Uri
{
internal void Method(T x, T y)
{
bool ok = x == y;
}
}

the user-defined overload is used. Same with other operators, of course.

But generally you want to do this with pre-defined value types and pre-defined operators, for example T is some numeric type (struct), and you want == (equality) or * (multiplication) or << (bit shift on integer) or similar. But that is not possible in C#.

It is possible to use dynamic instead of generic types, but obviously that is entirely different.

How to create interface with overloaded arithhmetic operators in C#?

This is not possible to create interface for implementing operators.

According to the Standard:

13.2 Interface members

The members of an interface must be methods, properties, events, or indexers. An
interface cannot contain constants, fields, operators, instance
constructors, destructors, or types, nor can an interface contain
static members of any kind
.

Constraints, generic variables and arithmetic operators

A StructName constraint wouldn't make sense, since you cannot inherit from value types.

If you had something like class Simple<T> where T : int you could only instantiate Simple<T> with T = int, no type inherits from int or any other value type for that matter.

C# (the CLR) lacks what other languages know as type classes, one popular mechanism to handle operator overloading without hard-coded compiler mechanics (like in C#).

Solution for overloaded operator constraint in .NET generics

There is no immediate answer; operators are static, and cannot be expressed in constraints - and the existing primatives don't implement any specific interface (contrast to IComparable[<T>] which can be used to emulate greater-than / less-than).

However; if you just want it to work, then in .NET 3.5 there are some options...

I have put together a library here that allows efficient and simple access to operators with generics - such as:

T result = Operator.Add(first, second); // implicit <T>; here

It can be downloaded as part of MiscUtil

Additionally, in C# 4.0, this becomes possible via dynamic:

static T Add<T>(T x, T y) {
dynamic dx = x, dy = y;
return dx + dy;
}

I also had (at one point) a .NET 2.0 version, but that is less tested. The other option is to create an interface such as

interface ICalc<T>
{
T Add(T,T)()
T Subtract(T,T)()
}

etc, but then you need to pass an ICalc<T>; through all the methods, which gets messy.

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