Strahinja Vladetic
Strahinja Vladetic

Reputation: 331

Aggregate extension for Dictionary C#

I am trying to create a generic Aggregate extension on Dictionary. Something like this..

void Main(){
    var foo = new Dictionary<string, Metric>();
    foo["first"] = new Metric(5);
    foo["sec"]  = new Metric(10);

    foo.Aggregate<string, Metric, int>("first", new Metric(5));
}

public class Metric : IAggregatable<int> {
    public int Total { get; set; }

    public Metric(int total) {
        Total = total;
    }

    public void Aggregate(int value) {
        Total += value;
    }
}

public static class DictionaryExtensions {
    public static void Aggregate<TKey, TValue, T>(this Dictionary<TKey, TValue> dic, TKey key, TValue value) where TValue : IAggregatable<T> {
        TValue result;
        if (dic.TryGetValue(key, out result))
            dic[key].Aggregate(value.Total);
        else
            dic[key] = value;
    }
}

public interface IAggregatable<T> {
    T Total { get; set; }
    void Aggregate(T value);
}

This works well but I have to specify the generic type arguments every time I make the call to Aggregate(...). This can be seen in main() as foo.Aggregate<string, Metric, int>("first", new Metric(5));. Is there a cleaner way to get this functionality because I would prefer to not have to specify the generic type parameters every time.

Upvotes: 0

Views: 140

Answers (1)

nvoigt
nvoigt

Reputation: 77304

I think your interface is a bit clunky. You don't need to know the internals of your metrics. To aggregate, you only need to know what can be aggregated, not how. The how can be handled by the implementation:

using System.Collections.Generic;

namespace ConsoleApplication3
{
    public class Metric : IAggregatable<Metric>
    {
        public int Total { get; set; }

        public Metric(int total)
        {
            Total = total;
        }

        public void Aggregate(Metric other)
        {
            Total += other.Total;
        }
    }

    public static class DictionaryExtensions
    {
        public static void Aggregate<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key, TValue value) where TValue : IAggregatable<TValue>
        {
            TValue result;
            if (dic.TryGetValue(key, out result))
                dic[key].Aggregate(value);
            else
                dic[key] = value;
        }
    }

    public interface IAggregatable<T>
    {
        void Aggregate(T other);
    }

    class Program
    {
        void Main()
        {
            var foo = new Dictionary<string, Metric>();
            foo["first"] = new Metric(5);
            foo["sec"] = new Metric(10);

            foo.Aggregate("first", new Metric(5));
        }        
    }
}

Upvotes: 4

Related Questions