tags:

views:

98

answers:

4

I'm writing a class that does essentially the same type of calculation for each of the primitive numeric types in C#. Though the real calculation is more complex, think of it as a method to compute the average of a number of values, e.g.

class Calc
{
    public int Count { get; private set; }
    public int Total { get; private set; }
    public int Average { get { return Count / Total; } }
    public int AddDataPoint(int data)
    {
        Total += data;
        Count++;
    }
}

Now to support that same operation for double, float and perhaps other classes that define operator + and operator /, my first thought was to simply use generics:

class Calc<T>
{
    public T Count { get; private set; }
    public T Total { get; private set; }
    public T Average { get { return Count / Total; } }
    public T AddDataPoint(T data)
    {
        Total += data;
        Count++;
    }
}

Unfortunately C# is unable to determine whether T supports operators + and / so does not compile the above snippet. My next thought was to constrain T to types that support those operators, but my initial research indicates this cannot be done.

It's certainly possible to box each of the types I want to support in a class that implements a custom interface e.g. IMath and restrict T to that, but this code will be called a great number of times and I want to avoid boxing overhead.

Is there an elegant and efficient way to solve this without code duplication?

A: 

You should be able to use an interface that the operation on it. Not done it myself but sounds like it should work. I don't think you can add the operator to the interface.

say something like

interface IAddable {
   void operator Add (int data);
}

then you should be able to limit your generic

class Calc<T>  where T : IAddable { 


    public int AddDataPoint(int data)
    {
        Total.Add(data);
        Count++;
    }
 }
Preet Sangha
Eric mentioned the option of restricted generic, and added that it's not suitable for his needs.
Neowizard
Correct, the boxing overhead is unacceptable in this case.
Eric J.
+2  A: 

Sadly enough, I have come across this same problem in C#. The ultimate solution is to use a language that lets you be a little bit more wacky with your generic arguments (I don't mean to insult C# here, the "wackyness" is not necessarily a good thing).

Basically, I got my inspiration from the IEquatable<T>/EqualityComparer<T> and IComparable<T>/Comparer<T> classes. Basically, you want something like an IMather<T> which has methods like Add(T a, T b) and Divide(T a, T b). Then, make associated implementations sealed class Int32Mather : IMather<int>. Finally, have a Mather<T> which gets the proper implementation (just like EqualityComparer<T>).

The advantage that this solution gives you is that you can just use the int and float types without having to box every single value, which will let you easily access them without having to cast or use LINQ's Select or whatever, which is pretty nice. It also cuts down on needless reference objects you create, which is nice for the garbage collector.

Painful? You bet it is! Unfortunately, this is the best way I know how to do it. If somebody has a better solution, I would love to know it.


For inlining: Naturally, you cannot guarantee anything about what runtime will do, because it has tons of crazy optimizations that you would never expect. However, you can help the system inline your calls if you want to.

Normally, you would have something like this:

class Points<T>
{
    readonly IMather<T> _mather;
    readonly IList<T> _list;

    // other code here

    public T Sum()
    {
        T val = _mather.DefaultValue();
        foreach (T t in _list)
            val = mather.Add(val, t);
        return val;
    }
}

Which seems totally legit. The problem is that it is pretty hard to inline that Add call, since it is an interface, which could be anything. The "solution" for this is to do something like:

class Points<T, TMather>
    where TMather : IMather<T>
{
    readonly TMather _mather;
    readonly IList<T> _list;

    // other code here

    public T Sum()
    {
        T val = _mather.DefaultValue();
        foreach (T t in _list)
            val = mather.Add(val, t);
        return val;
    }
}

So in the realization of the template, _mather has a type which has no virtual calls in it, which means the runtime can more easily inline the calls (if it wants to). The tradeoff here is more memory taken up for type definitions, which is pretty trivial and the fact that making these things is a little bit more obnoxious.

Travis Gockel
Do you know if the compiler will generally inline the calls to Add, Divide, etc?
Eric J.
Edited my answer for inlining.
Travis Gockel
+3  A: 

I ended up using Expressions, an approach outlined by Marc Gravell that I found by following links off of spinon's comment.

http://www.yoda.arachsys.com/csharp/genericoperators.html

Eric J.
Just make sure you cache the delegates and re-use them ;p
Marc Gravell
Note also that MiscUtils has a pre-built `Operator` class that provides all the necessary utility methods you are likely to need.
Marc Gravell
@Marc: Yes, I implemented your comment ;-)
Eric J.
Excellent solution!
Travis Gockel
A: 

There is an approach using dynamic in C# 4.0, it is not perfect obviously but it can bring a new light to the matter.

Details are in this blog post

Johann Blais