im only using c# 2.0
I had got part way to making a struct/interface wich wrapped all
the operators needed, but decided that generating code for the clases
its used on would be preferable, as its likly that only one of the many
diferent types would be used in any one project anyway.
Indeed. Well, let me know if you want a copy of the .NET 2.0 version -
but otherwise the interface apprach can be quite useful if you only
need to cope with known types (the version I have will work even with
custom structs).
Anyway - a simplified (few operators, few supported types) version of
the interface approach might look like below; note I've used a static
wrapper class in the middle (Calc) with generic methods; this means
you don't need to keep passing ICalc<Tinstance around, and type-
inference makes calling simple (i.e. note no explicit generics
mentioned in the body of Test<T>)
using System;
static class Program
{
static void Main()
{
int x = 5, y = 6;
int z = Test(x, y);
}
static T Test<T>(T x, T y)
{
T val = Calc.Add(x, y);
val = Calc.Multiply(x , Calc.Negate(val ));
return val;
}
}
public static class Calc
{
static Calc()
{
// known types
Register<int, CalcInt32>();
Register<float, CalcSingle>();
}
static void Register<TValue , TCalc>()
where TValue : struct
where TCalc : ICalc<TValue>, ICalc<TValue?>, new()
{
// handle both T and T?
TCalc calc = new TCalc();
CalcCache<TValu e>.Instance = calc;
CalcCache<TValu e?>.Instance = calc;
}
public static T Add<T>(T x, T y) {
return CalcCache<T>.In stance.Add(x, y);
}
public static T Multiply<T>(T x, T y)
{
return CalcCache<T>.In stance.Multiply (x, y);
}
public static T Negate<T>(T x)
{
return CalcCache<T>.In stance.Negate(x );
}
static class CalcCache<T>
{
private static ICalc<Tinstance = new CalcNotSupporte d<T>();
public static ICalc<TInstance
{
get
{
return instance;
}
set
{
if (instance == null) throw new
ArgumentNullExc eption("Instanc e");
instance = value;
}
}
}
}
interface ICalc<T>
{
T Add(T x, T y);
T Multiply(T x, T y);
T Negate(T x);
// etc
}
sealed class CalcNotSupporte d<T: ICalc<T>
{
public T Add(T x, T y) { throw new NotSupportedExc eption(); }
public T Multiply(T x, T y) { throw new NotSupportedExc eption(); }
public T Negate(T x) { throw new NotSupportedExc eption(); }
}
sealed class CalcInt32 : ICalc<Int32>, ICalc<Int32?>
{
public int Add(int x, int y) { return x + y; }
public int Multiply(int x, int y) {return x * y;}
public int Negate(int x) { return -x; }
public int? Add(int? x, int? y) { return x + y; }
public int? Multiply(int? x, int? y) { return x * y; }
public int? Negate(int? x) { return -x; }
}
sealed class CalcSingle : ICalc<Single>, ICalc<Single?>
{
public float Add(float x, float y) { return x + y; }
public float Multiply(float x, float y) { return x * y; }
public float Negate(float x) { return -x; }
public float? Add(float? x, float? y) { return x + y; }
public float? Multiply(float? x, float? y) { return x * y; }
public float? Negate(float? x) { return -x; }
}