2013-09-23 23 views
6

Muszę napisać coś, co nazywam Zbiornikiem agregacji, który przechowuje Agregacje, które są w zasadzie Czynnościami, które pobierają kolekcję obiektów i wyprowadzają jako wynik pojedynczy obiekt. Przykładami Agregacji byłyby: Średnia arytmetyczna, Mediana zbioru liczb, Średnia harmoniczna itd. Oto przykładowy kod.Agregacja i jak sprawdzić, czy możemy zsumować obiekty

var arithmeticMean = new Aggregation 
     { 
      Descriptor = new AggregationDescriptor { Name = "Arithmetic Mean" }, 
      Action = (IEnumerable arg) => 
      { 
       double count = 0; 
       double sum = 0; 

       foreach (var item in arg) 
       { 
        sum += (double)item; 
        count++; 
       } 

       return sum/count; 
      } 
     }; 

Oto mój problem z kodem. Przyjąłem, że obiekty były po prostu podwójne i dlatego dokonały konwersji. Co jeśli nie są podwójne? Jak mogę się upewnić, że mogę sumować dwa obiekty? Czy istnieje jakiś interfejs do tego w standardowych złożeń .Net? Potrzebuję czegoś podobnego do "do zrobienia" ... A może sam muszę to zaimplementować (wtedy będę musiał zawijać wszystkie prymitywne typy, takie jak double, int, etcetera, aby je obsłużyć).

Wszelkie porady dotyczące projektowania takich funkcji będą pomocne.

+1

Problemem nie jest to, że ciebie trzeba ustalić, czy kolekcja jest "podsumowująca". Wszystkie wartości liczbowe są z natury sumowane. Pytanie, które powinieneś zadać, brzmi "Czy' arg' to zbiór liczb? ". Możesz spróbować albo zapewnić silnie typowane odmiany 'Action' dla różnych typów liczbowych, albo środowisko wykonawcze rzuca na' arg'. – Jon

+0

Jon, dziękuję za odpowiedź. Wiem, że podane przeze mnie przykłady są liczbowe ... Ale naprawdę chciałbym napisać coś bardziej ogólnego i użytecznego. Nie chciałbym napisać kilka rzutów w środowisku wykonawczym, ale proponuję, aby działał z różnymi typami argumentów ... –

+3

Zobacz metody numerowane - ma zestaw ogólnych metod parametryzowanych z każdym typem obsługuje: 'Suma , Suma , Suma , Suma >' itp. Jest to jedyny sposób, aby parametr typu był "zsumowany" –

Odpowiedz

3

Spójrz na Enumerable metod klasy - to zestaw metod parametryzowane z każdego rodzaju, że obsługuje:

int Sum(this IEnumerable<int> source) 
double Sum(this IEnumerable<double> source) 
decimal Sum(this IEnumerable<decimal> source) 
long Sum(this IEnumerable<long> source) 
int? Sum(this IEnumerable<int?> source) 
// etc 

To jedyny sposób, aby metoda argumentu za „summable”.

Niestety nie można utworzyć ogólnej metody z generycznym type parameter constraint, która zezwala na typy tylko z przeciążonym operatorem +. Nie ma ograniczenia dla operatorów w .NET, również operatorzy nie mogą być częścią jakiegoś interfejsu (dlatego są statyczni). Nie można więc używać operatorów ze zmiennymi typu ogólnego.

Także jeśli będziesz wyglądać na .NET definicji typów prymitywnych, nie znajdzie żadnego interfejsu, który może ci pomóc tutaj - tylko porównanie, formatowania i konwersji są realizowane:

public struct Int32 : IComparable, IFormattable, IConvertible, 
         IComparable<int>, IEquatable<int> 
0

Możesz modyfikować swoją nieruchomość Action w klasie jak:

public Func<IEnumerable<double>, double> Action { get; set; } 

więc tylko wyjątkiem IEnumerable<double> i zwraca double wynik to.

+0

Tak naprawdę próbuję oddzielić od typu kolekcji, tak że mogę zsumować wszystko, co można w jakiś sposób podsumować. –

+1

@ george.zakaryan Następnie możesz utworzyć 2 przeciążenia dla akcji: 'Action (IEnumerable )' i 'Action (IEnumerable )', gdzie ISummable powinien być twoim interfejsem. Podwójnie niejawnie rzutuje na dowolny inny typ liczbowy. – selfnamed