views:

603

answers:

8

I want to write a method which can take an arbitrary array of a numeric type and return the sum of all the elements between startIndex and endIndex. This is what I have:

private static T SumArrayRange<T>(T[] scores, int startIndex, int endIndex)
{
    T score = 0;
    for (int i = startIndex; i <= endIndex; i++)
    {
        score += scores[i];
    }
    return score;
}

But the compilation fails with these 2 errors.

  • Cannot implicitly convert type 'int' to 'T'.
  • Operator '+=' cannot be applied to operands of type 'T' and 'T'

Is there any way I can force T to be only one of the numeric types (long, double etc.)? Or is their a more elegant way of solving this?

A: 

Add where T: struct, as in

private static T SumArrayRange<T>(T[] scores, int startIndex, int endIndex) where T: struct
{
   T score = defgault(T);    
   for (int i = startIndex; i <= endIndex; i++)    
   {        
      score += scores[i];    
   }    
   return score;
}

but testing this, even this won't work as the compiler cannot guarantee that the increment operator (+=) will work with any T that is a value type.....

Charles Bretana
Do all structs implmement the += operator?
Colin Mackay
A: 

This is because T could be any type. If T was a HttpWebRequest could you assign 0 to it, or could you use the += operator on it?

You can get around the first error by using

T score = default(T);

I'm not sure how you'd deal with the second because you'd have to constrain T to be types that implement a += operator.

Colin Mackay
+3  A: 

This approach works pretty well:

http://www.codeproject.com/KB/cs/genericnumerics.aspx

codekaizen
+1  A: 

There is no type to which you can constrain T that will allow the += operator to work. This is because .NET does not have a type that means numeric.

Bryan Watts
+6  A: 

No, there's no way to constrain generic type parameters to use operators, and there are no good workarounds for that, either. A proper one would be an interface such as INumeric or IArithmetic with methods such as Add, Subtract etc, implemented by all primitive types such as int and long. There is a 5-year old feature request for that in MS Connect, which is still Active. The latest word on that is:

Unfortunately, we've had to cut our plans to solve this problem in the .NET Framework 4.0.

Until then, you are relegated to either:

  • using Reflection yourself - messy and very slow
  • using any of the existing wrappers that will use Reflection for you (e.g. Microsoft.VisualBasic.CompilerServices.Operators class, with methods such as AddObject, SubtractObject etc which use reflection and implement VB semantics for the corresponding operators) - easy to use, but still very slow
  • hardcoding types you want to handle (i.e. no support for overloaded arithmetic operators on user-defined types), and using a giant if (x is int) ... else if (x is double) ... statement.
Pavel Minaev
A: 

Generic constraints are the only possiblilty I can think of. But, being drunk, I can't exactly test this!

Dan Diplo
+1 for using a technical forum while inebriated.
Charlie
A: 

I'm perhaps being stupid, but won't int.Parse() fix this problem?

Phoexo
+5  A: 

Another approach is to use the LINQ tools that are already available, rather than writing your own. For example:

var mySum = myCollection.Skip(startIndex).Take(count).Sum();

Since the Sum extension method exists for all of the built-in numeric types, you don't have to worry about writing your own. Of course, this won't work if your code's "myCollection" variable is already of a generic collection type.

Jacob