1

The objective is to create a simple program that calculates the sum of pre-processed set. The Sum must be generic to allow it accepts both integer and floating point set.

The following code does not compile. Could you tell me how to fix it?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{

    static class Program
    {
        delegate T del<T>(T x);
        static T Sum<T>(del<T> df, IEnumerable<T> data)
        {
            T s = 0;
            foreach (var x in data) s += df(x);
            return s;
        }

        static void Main(string[] args)
        {
            var data = Enumerable.Range(1, 4);
            int sum = Sum<int>(x => x * x, data);
            Console.WriteLine(sum);
        }
    }
}

Error Messages (roughly speaking):

  1. cannot convert int to T.
  2. += is not available for T.
kiss my armpit
  • 3,413
  • 1
  • 27
  • 50
  • `T s = 0;` should be `T s = default(T);` - Your other error however, cannot be easily solved. Since `T` could be any class (say, `object`), there might not be a `+` operator defined. – Blorgbeard Sep 05 '13 at 02:44
  • It's ugly, but you could handle the built in number types individually and [use reflection](http://stackoverflow.com/questions/1251507/is-it-possible-to-call-value-type-operators-via-reflection) to look for a + operator – TheEvilPenguin Sep 05 '13 at 02:50

4 Answers4

3

Ignoring the other issues with your code, you can't do what you're trying to do. C# does not support arithmetic operators on generic types.

Therefore, one option will be to Sum(del<int>, ..), Sum(del<float>, ...).. etc.

Or, use dynamic:

delegate T del<T>(T x);
static T Sum<T>(del<T> df, IEnumerable<T> data) 
{
    dynamic s = default(T);
    foreach (var x in data) s += df(x);
    return s;
}

This results is 30 for your provided example.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • 2
    No, there are many valid reasons to do this, C# is just poorly designed for it. In C++ it's trivial. – Ed S. Sep 05 '13 at 03:00
  • I could have sworn your post said "you *don't want to* do what you're trying to do", not "can't". Sorry if I misread that. – Ed S. Sep 05 '13 at 03:18
1

You can use the generic Add() method defined here.

The trick is to pass the initial value of s as the type T into the Sum() method instead of initializing it inside the function.

public class Program
{
    public static T Add<T>(T a, T b)
    {
        var paramA = Expression.Parameter(typeof (T), "a");
        var paramB = Expression.Parameter(typeof (T), "b");
        var body = Expression.Add(paramA, paramB);
        var add = Expression.Lambda<Func<T, T, T>>(body, paramA, paramB).Compile();
        return add(a, b);
    }

    public delegate T del<T>(T x);

    //pass the variable s into the function instead of initializing it inside the function.
    public static T Sum<T>(T s, del<T> df, IEnumerable<T> data)
    {
        return data.Aggregate(s, (current, x) => Add(current, df(x)));
    }

    public static void Main(string[] args)
    {
        var data = Enumerable.Range(1, 4);
        int sum = Sum(0, x => x * x, data);
        Console.WriteLine(sum);
    }
}
zs2020
  • 53,766
  • 29
  • 154
  • 219
0

You need to use the default keyword, specifically:

// was: T s = 0;
T s = default(T);

I replied in haste to the question in the title, on the secondary issue of performing add operations between generics, this has been covered in another StackOverflow question, so I wont double post. It involves using dynamic, which means you no longer have compile-time safety. Read the other question for more details.

Community
  • 1
  • 1
Timothy Walters
  • 16,866
  • 2
  • 41
  • 49
0

VERY similar to Simon Whitehead answer

    static T Sum<T>(del<T> df, dynamic data)
    {
        T s = default(T);
        foreach (var x in data) s += df(x);
        return s;
    }

this return also 30

Fredou
  • 19,848
  • 10
  • 58
  • 113