2010-11-09 12 views
11

Mam strukturę pieniężną z walutą i kwotą. Chciałbym móc podsumować listę za pomocą linq.Czy można przeciążać Sum, aby dodać typy niestandardowe?

public struct Money 
{ 
    public string Currency { get; set; } 
    public decimal Amount { get; set; } 

    public static Money operator +(Money m1, Money m2) 
    { 
     if (m1.Currency != m2.Currency) 
      throw new InvalidOperationException(); 

     return new Money() { Amount = m1.Amount + m2.Amount, Currency = m1.Currency }; 
    } 
} 

Biorąc pod uwagę powyższy kod, jeśli mam listę elementów, które mają obiekty wartości pieniądza jest to możliwe, aby uzyskać funkcji Sum do pracy z obiektem wartości pieniądza.

tj

Items.Sum(m => m.MoneyValue); 
+0

Właściwie wygląda na to, że Twój + nie będzie w 100% zadowolony z sumy ogólnej MiscUtil, z powodu użycia 'default (T)'; Zastanawiam się, czy powinieneś zmienić 'Money' na bardziej hojny - tzn.' SomeValue + default (Money) => someValue' –

+2

Również - mutable struct; * awoooga *, * awoooga * ... –

Odpowiedz

22
public static class SumExtensions 
{ 
    public static Money Sum(this IEnumerable<Money> source) 
    { 
     return source.Aggregate((x, y) => x + y); 
    } 

    public static Money Sum<T>(this IEnumerable<T> source, Func<T, Money> selector) 
    { 
     return source.Select(selector).Aggregate((x, y) => x + y); 
    } 
} 

Zastosowanie:

IEnumerable<Money> moneys = ... 
Money sum = moneys.Sum(); 

i

IEnumerable<Transaction> txs = ... 
Money sum = txs.Sum(x=>x.Amount); 
+0

+1. Ładne i czyste. – Steven

+0

Czy możesz również zapewnić korzystanie z tych metod? –

+0

prawdopodobnie chcesz upublicznić tę klasę. zająłem minutę, aby zrozumieć, dlaczego moje nie było kompilacji (zdefiniowane w różnych DLL) –

0

To powinno działać, jeśli wrócisz m.MoneyValue.Amount zamiast - nie a set of Sum overloads that accept a Func.

Niestety Sum nie jest zgodny z żadnym zdefiniowanym przez użytkownika operator+. (W rzeczywistości nie można było wywołać operator+ bez użycia odbicia.)

+0

PO powinien mieć świadomość, że nie uwzględni to różnych walut na liście. – TeaDrivenDev

3

Operatorzy to ból. Jednak jeśli spojrzysz na MiscUtil, zaimplementowałem ogólny , który ma względem operatorów niestandardowych. Użycie jest (celowo) identyczne - tak linia:

var moneySum = Items.Sum(m => m.MoneyValue); 

powinny działać, z oczekiwanego rezultatu - wyjątkiem, że obecnie nie obsługuje default(Money) celach kwasami. Ewentualnie, jeśli jest to tylko dla MoneyValue, wystarczy napisać metodę rozszerzenia:

public static class MoneyExtensions { 
    public static Money Sum(this IEnumerable<Money> source) { 
     Money sum = source.First(); 
     foreach(var item in source.Skip(1)) sum += item; 
     return sum; 
    } 
} 

Faktycznie, w celu uniknięcia 2 wyliczeń, mogę podkręcić do tego:

using (var iter = source.GetEnumerator()) 
{ 
    if (!iter.MoveNext()) return default(Money); 
    var sum = iter.Current; 
    while (iter.MoveNext()) sum += iter.Current; 
    return sum; 
} 
Powiązane problemy