17

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.

Thom Smith
  • 13,916
  • 6
  • 45
  • 91
  • 3
    Unfortunately, the type constraint does not allow you to require that the type supports arithmethic operators. What I find interesting is that in the BCL source code for e.g. `Int32` you will find a `IArithmetic` interface in the inheritance list that is commented out. This is pure speculation on my part but if Microsoft enabled that interface in the BCL then you could perhaps specify `IArithmetic` as a constraint to allow you to write your own generic classes with arithmetic. – Martin Liversage Jun 08 '12 at 15:18
  • Link to similar question: http://stackoverflow.com/q/4039694/613130 – xanatos Mar 07 '17 at 11:05

6 Answers6

8

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

More than 10 years have past since I answered this question and finally the C# 11 feature - static virtual members in interfaces was introduced in .NET 7 allowing us to do Generic math and many other things.

Interfaces can now declare static factory methods not limiting us to use parameter-less constructors in generic contexts.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • What do you mean "`struct` constraints aren't allowed"? – Kirk Woll Jun 08 '12 at 15:43
  • You actually can. See [Constraints on Type Parameters (C# Programming Guide)](http://msdn.microsoft.com/en-us/library/d5x73970.aspx). – Olivier Jacot-Descombes Jun 08 '12 at 16:02
  • 1
    @AdamHouldsworth: Structs can implement interfaces! Since structs cannot inherit from each other, restricting to a certain struct type would be the same as not having a generic parameter at all (or you would have exactly one valid generic type parameter, namely this one struct)! – Olivier Jacot-Descombes Jun 08 '12 at 19:01
  • @OlivierJacot-Descombes Apologies, I'll redact my earlier comments. I don't think I'd ever bother with a struct in an interface, too much room for shenanigans. I wasn't thinking too much about the specifics of structs, it was just a passing comment. – Adam Houldsworth Jun 08 '12 at 20:11
  • 1
    What I want to says is that you can restrict the generic type of a struct if it implements an interface. `where T : struct, INumber` – Olivier Jacot-Descombes Jun 09 '12 at 00:17
  • Not Operators themselves but you can now have static methods in interfaces, and the default numeric types implement interfaces with methods for all operators: https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/ – blenderfreaky Nov 21 '21 at 16:09
7

It's coming!

Check out this .NET Blog post.

Starting in .NET 6, support for this can be enabled if you are willing to enable language preview features. This means that there is no guarantee that the functionality will be present (or work in the same way) in later versions of the framework (.NET 7+).

If you are fine with this, keep reading to see how this can be enabled for your project. You will be able to make use of interfaces such as INumber and IFloatingPoint to create programs such as:

using System;

Console.WriteLine(Sum(1, 2, 3, 4, 5));
Console.WriteLine(Sum(10.541, 2.645));
Console.WriteLine(Sum(1.55f, 5, 9.41f, 7));

static T Sum<T>(params T[] numbers) where T : INumber<T>
{
    T result = T.Zero;

    foreach (T item in numbers)
    {
        result += item;
    }

    return result;
}

INumber currently comes from the System.Runtime.Experimental NuGet package. My project file for the sample above looks like

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <EnablePreviewFeatures>true</EnablePreviewFeatures>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <LangVersion>preview</LangVersion>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="System.Runtime.Experimental" Version="6.0.0" />
    </ItemGroup>

</Project>

There are also interfaces such as IAdditionOperators and IComparisonOperators so you can make use of specific operators generically.

I've honestly been waiting a really long time for this to be supported.

Per Lundberg
  • 3,837
  • 1
  • 36
  • 46
Dan
  • 7,286
  • 6
  • 49
  • 114
5

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);
Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
5

yes, it can be done by using dynamic type variables.

example:

T Add(T value1, T value2)
{           
        dynamic a = value1;
        dynamic b = value2;
        return (a + b);
}

for more reference please click here

Community
  • 1
  • 1
Ujjwal
  • 61
  • 1
  • 1
4

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;
    }
}
Sachin
  • 93
  • 1
  • I am a beginner in c# and any simple explanation is important therefore if someone votes down, I would appreciate comment on that! Now, could someone (else) please explain why has this answer got vote down? Why this approach is not correct? – Celdor Jul 29 '16 at 07:20
  • 4
    @Celdor: first, it's going to be slow, because you're doing RTTI and comparing strings. Second, it's not really generic if I have to add every type manually... – Paulius Liekis Dec 25 '16 at 21:25
  • 1
    Recently the jit has introduced optmization detecting typeof(T) and removing dead branches based on RTTI conditions. This solution, with proper modifications, can run faster than other answers. – Luca Mar 07 '17 at 12:19
0

Tangentially related answer, in regards to arithmetic with Enums and generics.

If you are looking specifically for bitwise operators such as '&', |, ^ for use with Enums as a generic constraint; adding IConveritible as a constraint in addition to System.Enum is a viable work around.

public static bool Contains<T>(this T container, T Value) where T : Enum, IConvertible
{
    return (container.ToInt32(null) & Value.ToInt32(null)) != 0;
}

public static T Insert<T>(this ref T container, T Value) where T : struct, Enum, IConvertible
{
    // this is slow and a proof of concept, not recommend for frequent use
    container = (T)Enum.ToObject(typeof(T), container.ToInt32(null) | Value.ToInt32(null));

    return container;
}
DekuDesu
  • 2,224
  • 1
  • 5
  • 19