2013-07-18 13 views
6

Mam obiekt reprezentujący dane biznesowe.Suma Linq na obiektach?

Zasadniczo, jest to obiekt agregating pewne sumy:

public class MyClass{ 
    public double MyDataOne {get;set;} 
    public double MyDataTwo {get;set;} 
    public double MyDataThree {get;set;} 

    public static MyClass operator +(MyClass data1, MyClass data2){ 
     return new MyClass{MyDataOne = data1.MyDataOne + data2.MyDataOne, MyDataTwo=data1.MyDataTwo+data2.MyDataTwo, MyDataThree=data1.MyDataThree+data2.MyDataThree }; 
    } 
} 

Teraz, jeśli mam się IEnumerable<MyClass> myClasses, Czy istnieje somethings mogę wdrożyć w MojaKlasa, aby ten :?

myClasses.Sum(d=>d); 

Bo dla mnie sposób obiekt jest additioned musi być znajomość przedmiotu i nie wywołujący (jeśli jeden dzień mam jeden więcej danych, nie chcę patrzeć w całym moim kodu aby zobaczyć, gdzie jest używany).

Dziękuję

+0

http://stackoverflow.com/a/13661394/1714342 Wyjaśnia ona coś – wudzik

Odpowiedz

4

Napisz własną metodę rozszerzenia:

public static MyClass Sum(this IEnumerable<MyClass> source) 
{ 
    var result = new MyClass(); // all data will be zeros 

    foreach(var item in source) 
     result = result + item; 

    return result; 
} 

Zastosowanie:

var sum = myClasses.Sum(); 
+1

A jeśli możesz również uczynić go bardziej ogólnym poprzez wprowadzenie interfejsu o nazwie "ISumable" i zrobić ogólne rozszerzenie dla wszystkich 'IEnumerable gdzie T: ISumable ':) – wudzik

+1

@wudzik' YAGNI' :) Ma tylko jedną klasę biznesową z tym zachowaniem. –

+0

@wudzik Dziękuję. Dodam tylko, że tworzę interfejs, aby zapewnić, że klasa, której sumę zaimplementuję, używa metody "Sum", która pobiera listę parametru IEnumerable w parametrze. W ten sposób nie tworzę wielu pośrednich elementów – J4N

5

Możesz napisać własną metodę rozszerzenia, która otacza połączenia do IEnumerable<T>.Aggregate co z kolei wywołuje numer przeciążony: operator +:

public static MyClass Sum(this IEnumerable<MyClass> collection) 
{ 
    return collection.Aggregate((a, b) => a + b); 
} 

ten będzie nazywany przez:

MyClass sum = myClasses.Sum(); 

lub nawet pójść o krok dalej, uogólniać i obejmują selektora:

public static MyClass Sum<T>(this IEnumerable<T> collection, 
    Func<T, MyClass> selector) 
{ 
    return collection.Aggregate(new MyClass() /*start with an empty MyClass*/, 
     (a, b) => a + selector(b)); 
} 

To byłoby nazwać jak sugerujesz:

MyClass sum = myClasses.Sum(d => d); 

Oprócz typów złożonych zawierających MyClass na przykład:

class Foo 
{ 
    public MyClass Bar {get; set;} 
    public int Baz {get; set;} 
} 

var FooList = new List<Foo>(); 

MyClass sumOfFooListsBars = FooList.Sum(f => f.Bar); 
0

Aby korzystać Sum należy podać Func<MyClass, ###> delegata, gdzie ### jest int, long, float, double, decimal lub ich odpowiedniki zerowalne. Nie możesz więc używać MyClass w sposób, w jaki chcesz.

Wszystkie przeciążenia metody Sum zwracają typy pierwotne, które wymieniono powyżej. Dlatego nie ma sensu sumowanie niestandardowego obiektu, a zwracany typ nie jest liczbą, ale także obiektem niestandardowym.