2013-03-14 32 views
5

Làm cách nào để nhận được tổng các số trong bộ sưu tập các đối tượng IEnumerable? Tôi biết chắc chắn rằng loại cơ bản sẽ luôn là số nhưng loại được xác định khi chạy.Làm thế nào để có được tổng số linq của IEnumerable <object>

IEnumerable<object> listValues = data.Select(i => Convert.ChangeType(property.GetValue(i, null), columnType)); 

Sau đó tôi muốn để có thể làm như sau (sau đây có lỗi: "Không thể giải quyết phương pháp Sum"):

var total = listValues.Sum(); 

Bất kỳ ý tưởng? Cảm ơn bạn.

+1

Tại sao chính xác loại xác định tại thời gian chạy? Nghe có vẻ rất cá! – sdfgsdfg

+0

Nếu loại được xác định trong thời gian chạy, có vẻ như là một công việc cho Generics. Bạn có quyền truy cập vào việc tạo danh sách 'IEnumerable listValues' không? Bạn có thể thay đổi nó thành 'IEnumerable trong đó T: struct, IConvertible'? – Tory

+0

@Tory - vâng tôi có quyền truy cập vào việc tạo IEnumerable nhưng tôi không biết chính xác cách thực hiện thay đổi bạn đang đề xuất. Tôi mới vào thế giới Generics, xin vui lòng cung cấp một ví dụ, cảm ơn bạn. – Mike

Trả lời

4

Bạn có thể sử dụng cây biểu thức để tạo ra các yêu cầu chức năng add, sau đó gấp trên danh sách đầu vào của bạn:

private static Func<object, object, object> GenAddFunc(Type elementType) 
{ 
    var param1Expr = Expression.Parameter(typeof(object)); 
    var param2Expr = Expression.Parameter(typeof(object)); 
    var addExpr = Expression.Add(Expression.Convert(param1Expr, elementType), Expression.Convert(param2Expr, elementType)); 
    return Expression.Lambda<Func<object, object, object>>(Expression.Convert(addExpr, typeof(object)), param1Expr, param2Expr).Compile(); 
} 

IEnumerable<object> listValues; 
Type elementType = listValues.First().GetType(); 
var addFunc = GenAddFunc(elementType); 

object sum = listValues.Aggregate(addFunc); 

lưu ý điều này đòi hỏi danh sách đầu vào là không có sản phẩm nào, nhưng nó có lợi thế giữ nguyên kiểu phần tử trong kết quả.

+0

giải pháp của bạn hoạt động hoàn toàn tốt đẹp! chỉ cố gắng hiểu toàn bộ khái niệm. Cảm ơn bạn. – Mike

10

Nếu bạn biết chính xác loại luôn luôn sẽ là một loại số, bạn sẽ có thể sử dụng một cái gì đó như:

double total = listValues.Sum(v => Convert.ToDouble(v)); 

này sẽ làm việc vì Convert.ToDouble sẽ tìm kiếm IConvertible, được thực hiện bởi các loại số lõi. Bạn đang buộc loại này là double và không phải là loại ban đầu.

+0

Hãy nhớ rằng điều này có thể ném một 'InvalidCastException' cho ví dụ: dây và các đồ vật khác! –

+0

@ bebeeb - điều đó đúng, mã trước cuộc gọi đó đảm bảo rằng chỉ có các loại số được chuyển đến điểm đó. – Mike

+0

Reed - giải pháp của bạn rất đơn giản và hoạt động tốt, nhưng tôi muốn giữ nguyên kiểu gốc. – Mike

-1
static void Main(string[] args) 
{ 
    var sum = GetData().TryCast<double>.Sum(); 
} 

private static IEnumerable<object> GetData() 
{ 
    yield return 4.478; 
    yield return 4f; 
    yield return 0xFF; 
    yield return false; 
    yield return new List<string> { "foo", "bar" }; 
} 

// the extension function 
public static IEnumerable<T> TryCast<T>(this IEnumerable<object> values) 
{ 
    foreach (var v in values) 
    { 
     T a = default(T); 
     try 
     { 
      a = (T) Convert.ChangeType(v, typeof (T)); 
     } 
     catch (FormatException) 
     { 
     } 
     yield return a; 
    } 
} 

tôi thấy nó khá mùi, rằng DB của bạn trả về loại phi xác định các giá trị. Phương pháp mở rộng LINQ này cung cấp một số (!) Loại an toàn và không ném ngoại lệ như Convert.ToDouble() sẽ làm, ngay cả khi bạn trả lại các toán tử và đối tượng.

+1

Điều này không trả lời câu hỏi. Câu hỏi đặt ra là nếu bạn có một bộ sưu tập của IEnumerable làm thế nào để bạn tổng hợp nó? –

+0

Tôi xin lỗi, tôi sẽ chỉnh sửa lại. Tôi mặc dù vấn đề của bạn là LINQ. –

+0

Tôi đã cập nhật câu trả lời của mình cho phù hợp. :) –

0

chuyển đổi thành một loại. Nói, thập phân.

data.Select(i => Convert.ToDecimal(property.GetValue(i, null)).Sum();

0

bạn có thể sử dụng dyanmic, hoạt động hoàn hảo:

listValues.Sum(x => (dynamic)x); 
+0

Trong kịch bản của tôi giải pháp này chỉ hoạt động khi loại cơ bản là int. – Mike

Các vấn đề liên quan