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
How to Properly Exit a C# Application
How to Merge Multiple Assemblies into One
Difference Between Ref and Out Parameters in .Net
Delegate Keyword VS. Lambda Notation
How Would You Do a "Not In" Query with Linq
Fixed Size Queue Which Automatically Dequeues Old Values Upon New Enques
Using Linq to Group a List of Objects into a New Grouped List of List of Objects
Specifying a Custom Datetime Format When Serializing with JSON.Net
Creating a Generic<T> Type Instance with a Variable Containing the Type
Detect If Running as Administrator with or Without Elevated Privileges
How to Know If a Process Is Running
Inner Join of Datatables in C#
Which Tls Version Was Negotiated
How to Concatenate Two Arrays in C#
The Cast to Value Type 'Int32' Failed Because the Materialized Value Is Null