2013-09-23 5 views
6

Ho bisogno di scrivere qualcosa che chiamo Contenitore di aggregazione, che memorizza Aggregazioni, che sono essenzialmente Azioni che accettano una raccolta di oggetti e producono un singolo oggetto come risultato. Esempi di aggregazioni sarebbero: Media aritmetica, mediana di un insieme di numeri, media armonica ecc. Ecco un codice di esempio.Aggregazione e come verificare se è possibile sommare gli oggetti

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; 
      } 
     }; 

Ecco il mio problema con il codice. Ho assunto che gli oggetti fossero solo il doppio e quindi hanno fatto una conversione. Cosa succede se non sono il doppio? Come posso assicurarmi che mi sia consentito sommare due oggetti? Esiste una sorta di interfaccia per questo negli assiemi .Net standard? Ho bisogno di qualcosa come ISummable ... O ho bisogno di implementarlo da solo (quindi dovrò avvolgere tutti i tipi primitivi come double, int, eccetera per supportarlo).

Qualsiasi consiglio relativo alla progettazione di tale funzionalità sarà utile.

+1

Il problema non è che si è necessario determinare se una raccolta è "sommabile". Tutti i valori numerici sono intrinsecamente sommabili. La domanda che dovresti porre è invece "Is 'arg? Una raccolta di numeri?". Puoi provare a fornire variazioni fortemente tipizzate di 'Action' per diversi tipi numerici, o cast di esecuzione su' arg'. – Jon

+0

Jon, grazie per la risposta. Lo so, gli esempi che ho dato sono tutti numerici ... Ma mi piacerebbe davvero scrivere qualcosa di più generico e utile. Non mi piacerebbe scrivere un sacco di cast di esecuzione lì, ma suggerisco che un insieme di Azioni con diversi tipi di argomenti funzionerebbe qui ... –

+3

Dai un'occhiata a Metodi Enumerabili - ha set di metodi generici parametrizzati con ogni tipo supporta: 'Sum , Sum , Sum , Sum >' ecc. Questo è l'unico modo per rendere il parametro di tipo "sommabile" –

risposta

3

Date un'occhiata su Enumerable metodi di classe - è un insieme di metodi parametrizzati con ogni tipo che supporta:

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 

Questo è l'unico modo per rendere il metodo argomento di essere 'sommabile'.

Sfortunatamente non è possibile creare un metodo generico con type parameter constraint generico, che consentirà il sovraccarico solo dei tipi con operatore +. Non esiste alcun vincolo per gli operatori in .NET, anche gli operatori non possono far parte di alcune interfacce (quindi sono statici). Quindi, non è possibile utilizzare operatori con variabili di tipo generico.

anche se si guarderà sul .NET definizioni primitivi tipi, non troverete alcuna interfaccia che può aiutare qui - solo il confronto, la formattazione e la conversione sono attuate:

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

È possibile modificare la vostra proprietà Action nella classe come:

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

Quindi sarebbe solo tranne IEnumerable<double> e restituisce un risultato double.

+0

In realtà sto cercando di astrarre dal tipo di collezione, in modo da poter riassumere tutto ciò che può essere sommato in qualche modo. –

+1

@ george.zakaryan Quindi puoi creare 2 overload per Azione: 'Azione (IEnumerable )' e 'Azione (IEnumerable )' dove ISummable dovrebbe essere la tua interfaccia. Il doppio ricalca implicitamente a qualsiasi altro tipo numerico. – selfnamed