Lee wrote:
I'd like to implement a generic class that takes as its Type-parameter
a numeric type (e.g. (U)Int16/32/64, float, double, decimal, etc.).
The problem is that, having validated the Type-parameter, I cannot do
any arithmetic operations (+, -, *, /) on variables of that type.
I tried creating wrapper-classes for the numeric types I will support
and tried to derive them from a custom interface that specified the
above 4 operators -- but interfaces are not allowed to specify
operators.
I'm fairly sure this problem has arisen before and I'm hoping someone
can point me to a viable solution.
You need to use an abstract base class or (preferably) an interface that
defines the operations you want as methods. You can't do it just with
operators.
The general pattern is the same as with IComparer<Tand
IEqualityComparer<T- these provide equivalents of '<' and '=='
respectively, in the form of Compare and Equals, respectively.
You then pass an implementation of your IArithmetic<Tto your generic
class's constructor, or methods that require such operations. If you do
it right, you can even avoid virtual / interface method calls:
---8<---
using System;
interface IArithmetic<T>
{
T Add(T l, T r);
}
struct Int32Arithmetic: IArithmetic<int>
{
public int Add(int l, int r) { return l + r; }
}
class App
{
static T Sum<T,TOps>(T[] array, TOps ops)
where TOps: IArithmetic<T>
{
T result = default(T);
foreach (T item in array)
result = ops.Add(result, item);
return result;
}
static void Main()
{
int[] values = { 10, 20, 30 };
Console.WriteLine(
Sum<int,Int32Arithmetic>(values,
new Int32Arithmetic()));
}
}
--->8---
The calls to ops.Add above are resolved statically due to (1) TOps being
constrained to an interface, (2) the implementation type specified
directly, and (3) the concrete implementation of the interface being on
a sealed type, such as a struct.
Obviously, if you're doing lots of this, you'll want to specify TOps &
ops in a descendant class & constructor, to avoid verbosity.
With appropriate reflection tricks, an equivalent to Comparer<T>.Default
(that might be called Arithmetic<T>.Default, for example) can be
created.
-- Barry
--
http://barrkel.blogspot.com/