views:

800

answers:

9

Hi All,

I'm trying to figure a way to create a generic class for number types only, for doing some calculations.

Is there a common interface for all number types (int, double, float...) that I'm missing???

If not, what will be the best way to create such a class?

UPDATE:

The main thing I'm trying to achieve is checking who is the bigger between two variables of type T.

A: 

No a T is for everything.

You would have to check the type inside your method and reject it.

David Basarab
You can constrain T to conform to a specific type, but not to conform to one of several specific types. http://msdn.microsoft.com/en-us/library/d5x73970%28VS.80%29.aspx
STW
+4  A: 

As far as I know this is not possible. You may find some reasons why (and alternative solutions) here.

Fredrik Mörk
+2  A: 

Closest you get is struct I'm afraid. You'll have to do more extensive checks for number types in code.

public class MyClass<T> where T : struct
(...)
Dag
+1  A: 

I don't believe you can define that using a generic type constraint. Your code could internally check your requirements, possibly using Double.Parse or Double.TryParse to determine if it is a number--or if VB.NET isn't out of the question then you could use the IsNumeric() function.

Edit: You can add a reference to Microsoft.VisualBasic.dll and call the IsNumeric() function from c#

STW
+5  A: 

You cannot do this, since you'd have to use a single interface for arithmetic operations. There have been many requests on Connect to add an IArithmetic interface for this specific purpose, but so far they've all been rejected.

You can sort of work around this by defining a struct with no members, which implements a "Calculator" interface. We took this approach in an interpolation generic class in the Pluto Toolkit. For a detailed example, we have a "vector" calculator implementation here, which lets our generic interpolator work with vectors. There are similar ones for floats, doubles, quaternions, etc.

Reed Copsey
+2  A: 

In the Framework BCL (base class library), many numeric functions (such as the functions in System.Math) deal with this by having overloads for each numeric type.

The static Math class in the BCL contains static methods, which you can call without having to create an instance of the class. You could do the same in your class. For example, Math.Max has 11 overloads:

public static byte Max(byte val1, byte val2);
public static decimal Max(decimal val1, decimal val2);
public static double Max(double val1, double val2);
public static short Max(short val1, short val2);
public static int Max(int val1, int val2);
public static long Max(long val1, long val2);
public static sbyte Max(sbyte val1, sbyte val2);
public static float Max(float val1, float val2);
public static ushort Max(ushort val1, ushort val2);
public static uint Max(uint val1, uint val2);
public static ulong Max(ulong val1, ulong val2);
Robert Harvey
+2  A: 

There are interfaces for some of the operations on the number types, like the IComparable<T>, IConvertible and IEquatable<T> interfaces. You can specify that to get a specific functionality:

public class MaxFinder<T> where T : IComparable<T> {

   public T FindMax(IEnumerable<T> items) {
      T result = default(T);
      bool first = true;
      foreach (T item in items) {
         if (first) {
            result = item;
            first = false;
         } else {
            if (item.CompareTo(result) > 0) {
               result = item;
            }
         }
      }
      return result;
   }

}

You can use delegates to expand a class with type specific operations:

public class Adder<T> {

   public delegate T AddDelegate(T item1, T item2);

   public T AddAll(IEnumerable<T> items, AddDelegate add) {
      T result = default(T);
      foreach (T item in items) {
         result = add(result, item);
      }
      return result;
   }

}

Usage:

Adder<int> adder = new Adder<int>();
int[] list = { 1, 2, 3 };
int sum = adder.AddAll(list, delegate(int x, int y) { return x + y; });

You can also store delegates in the class, and have different factory methods that sets up delegates for a specific data type. That way the type specific code is only in the factory methods.

Guffa
+5  A: 

What version of .NET are you using? If you are using .NET 3.5, then I have a generic operators implementation in MiscUtil (free etc).

This has methods like T Add<T>(T x, T y), and other variants for arithmetic on different types (like DateTime + TimeSpan).

Additionally, this works for all the inbuilt, lifted and bespoke operators, and caches the delegate for performance.

Some additional background on why this is tricky is here.

You may also want to know that dynamic (4.0) sort-of solves this issue indirectly too - i.e.

dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect


Re the comment about < / > - you don't actually need operators for this; you just need:

T x = ..., T y = ...
int c = Comparer<T>.Default.Compare(x,y);
if(c < 0) {
    // x < y
} else if (c > 0) { 
    // x > y
}
Marc Gravell
I'm using .NET 3.5, I tried to do "if(x > y)" while x and y of type T.
CD
MiscUtil has Operator.GreaterThan, but you don't even need this; will update to show why not...
Marc Gravell