2010-11-09 17 views
11

Tôi có cấu trúc Tiền có tiền tệ và số tiền. Tôi muốn có thể tổng hợp một Danh sách bằng cách sử dụng LINQ.Bạn có thể quá tải Tổng cộng để thêm các loại tùy chỉnh

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

Cho mã trên nếu tôi có danh sách các mục có đối tượng giá trị tiền, bạn có thể nhận hàm Sum hoạt động với đối tượng giá trị tiền.

tức

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

Thực ra, có vẻ như + của bạn sẽ không hài lòng 100% với tổng MiscUtil chung, do sử dụng 'mặc định (T)'; Tôi tự hỏi liệu bạn có nên thay đổi 'Tiền' thành hào phóng hơn không - tức là 'someValue + default (Money) => someValue' –

+2

Ngoài ra - cấu trúc có thể thay đổi; * awoooga *, * awoooga * ... –

Trả lời

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

Cách sử dụng:

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

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

+1. Đẹp và sạch sẽ. – Steven

+0

bạn có thể vui lòng cung cấp cách sử dụng các phương pháp này không? –

+0

có thể bạn sẽ muốn đặt lớp đó thành công khai. đã cho tôi một phút để nhận ra lý do tại sao tôi không biên dịch (được định nghĩa trong DLL khác nhau) –

0

này nên có tác dụng nếu bạn quay lại m.MoneyValue.Amount thay vì - có a set of Sum overloads that accept a Func.

Thật không may Sum không tuân theo bất kỳ operator+ nào bạn xác định. (Trong thực tế, nó không thể gọi operator+ mà không sử dụng phản ánh.)

+0

OP nên lưu ý rằng điều này sẽ không tính các loại tiền tệ khác nhau trong danh sách. – TeaDrivenDev

3

Các nhà khai thác là một nỗi đau. Tuy nhiên, nếu bạn nhìn vào số MiscUtil, tôi đã triển khai một số chung Enumerable.Sum rằng sẽ tôn trọng các toán tử tùy chỉnh. Việc sử dụng là (cố ý) giống hệt nhau - vì vậy dòng của bạn:

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

nên làm việc, với kết quả mong đợi - trừ rằng hiện tại bạn không xử lý default(Money) cho mục đích bổ sung. Ngoài ra, nếu đây là chỉ cho MoneyValue, chỉ cần viết một phương pháp khuyến nông:

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

Trên thực tế, để tránh 2 enumerations, tôi có thể tinh chỉnh này để:

using (var iter = source.GetEnumerator()) 
{ 
    if (!iter.MoveNext()) return default(Money); 
    var sum = iter.Current; 
    while (iter.MoveNext()) sum += iter.Current; 
    return sum; 
} 
Các vấn đề liên quan