Implementing arithmetic in generics?
Is it possible to implement basic arithmetic (at least addition) in C# generics, like you can with C++ templates? I've been trying for a while to get them up and working, but C# doesn't let you declare the same generic type multiple times, like you can with templates.
Extensive googling did not provide an answer.
EDIT: Thanks, but what I'm looking for is a way to do the arithmetic at compile time, embedding something like Church numerals in generics types. That's why I linked the article that I did. Arithmetic in generic types, not arithmetic on instances of generic types.
Solution 1:
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);
}
}
Solution 2:
Please feel free to offer more clarification if my answer seems off-kilter.
There are no generic constraints on operators in the C# language, at least. As Jon Skeet has proven with Unconstrained Melody, the constraints might actually be perfectly valid in the CLR itself.
The best you can do with constraints is provide interfaces / custom classes that expose the actions you need. You wouldn't be able to provide the primitive (unless you also implement the implicit
operator perhaps), but it would at least let you create generic code for the math part.
Generic constraints allow the compiler to infer the available members based on the lowest common denominator (as specified by the constraint or lack of). Most of the time, generics are unconstrained and thus give you only object
semantics.
Alternatively, avoid using constraints and use
dynamic
to temporarily store the generic variable and then make the assumption (via duck typing) that it has the relevant operators:
class Program
{
static void Main(string[] args)
{
var result = Add<int, long, float>(1, 2);
Console.WriteLine(result); // 3
Console.WriteLine(result.GetType().FullName); // System.Single
Console.Read();
}
static T3 Add<T1, T2, T3>(T1 left, T2 right)
{
dynamic d1 = left;
dynamic d2 = right;
return (T3)(d1 + d2);
}
}
This involves the DLR and will have some performance overhead (I don't have exact figures), especially if you intend the calculations to be performance-critical.
I'm not sure what you mean "declare the same generic type multiple times", this works:
class Tuple<T1, T2> // etc.
var myTuple = new Tuple<int, int>(1, 2);
Solution 3:
Friends, the intuitive answer to this in C# is RTTI and casting back and forth from the object class
enter code here
class MyMath
{
public static T Add<T>(T a, T b) where T: struct
{
switch (typeof(T).Name)
{
case "Int32":
return (T) (object)((int)(object)a + (int)(object)b);
case "Double":
return (T)(object)((double)(object)a + (double)(object)b);
default:
return default(T);
}
}
}
class Program
{
public static int Main()
{
Console.WriteLine(MyMath.Add<double>(3.6, 2.12));
return 0;
}
}