What would I do if I want to have a generic method that only accepts types that have overloaded an operator, for instance the subtraction operator. I tried using an interface as a constraint but interfaces can\'t have operator overloading.
What is the best way to achieve this?
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.
I found that IL can actually handle this quite well. Ex.
ldarg.0
ldarg.1
add
ret
Compiled in a generic method, the code will run fine as long as a primitive type is specified. It may be possible to extend this to call operator functions on non-primitive types.
See here.
There is a piece of code stolen from the internats that I use a lot for this. It looks for or builds using IL
basic arithmetic operators. It is all done within an Operation<T>
generic class, and all you have to do is assign the required operation into a delegate. Like add = Operation<double>.Add
.
It is used like this:
public struct MyPoint
{
public readonly double x, y;
public MyPoint(double x, double y) { this.x=x; this.y=y; }
// User types must have defined operators
public static MyPoint operator+(MyPoint a, MyPoint b)
{
return new MyPoint(a.x+b.x, a.y+b.y);
}
}
class Program
{
// Sample generic method using Operation<T>
public static T DoubleIt<T>(T a)
{
Func<T, T, T> add=Operation<T>.Add;
return add(a, a);
}
// Example of using generic math
static void Main(string[] args)
{
var x=DoubleIt(1); //add integers, x=2
var y=DoubleIt(Math.PI); //add doubles, y=6.2831853071795862
MyPoint P=new MyPoint(x, y);
var Q=DoubleIt(P); //add user types, Q=(4.0,12.566370614359172)
var s=DoubleIt(\"ABC\"); //concatenate strings, s=\"ABCABC\"
}
}
Operation<T>
Source code courtesy of paste bin: http://pastebin.com/nuqdeY8z
with attribution below:
/* Copyright (C) 2007 The Trustees of Indiana University
*
* Use, modification and distribution is subject to the Boost Software
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Authors: Douglas Gregor
* Andrew Lumsdaine
*
* Url: http://www.osl.iu.edu/research/mpi.net/svn/
*
* This file provides the \"Operations\" class, which contains common
* reduction operations such as addition and multiplication for any
* type.
*
* This code was heavily influenced by Keith Farmer\'s
* Operator Overloading with Generics
* at http://www.codeproject.com/csharp/genericoperators.asp
*
* All MPI related code removed by ja72.
*/