2016-02-24 16 views
40

Trong khi làm việc với các phần mở rộng LINQ nó là bình thường để xem mã như thế này:Mở rộng LINQ để chấp nhận enumerables nullable

IEnumerable<int> enumerable = GetEnumerable(); 
int sum = 0; 
if (enumerable != null) 
{ 
    sum = enumerable.Sum(); 
} 

Nhằm nâng cao chất lượng mã, tôi đã viết các phương pháp khuyến nông sau đó kiểm tra các enumerables nullable và phá vỡ thực thi LINQ.

public static IEnumerable<T> IgnoreIfEmpty<T>(this IEnumerable<T> enumerable) 
{ 
    if (enumerable == null) yield break; 
    foreach (var item in enumerable) 
    { 
     yield return item; 
    } 
} 

Vì vậy, tôi có thể cấu trúc mã là như thế này:

var sum = GetEnumerable().IgnoreIfEmpty().Sum(); 

Câu hỏi của tôi bây giờ là:

  1. gì các hình phạt có liên quan đến phương pháp khuyến nông của tôi trong thời gian chạy?
  2. Có thực tiễn tốt để mở rộng LINQ theo cách đó không?

Cập nhật: khuôn khổ mục tiêu của tôi là: 3,5

+5

'IgnoreIfEmpty' không phải là một tên tuyệt vời, vì" Bỏ qua "là mơ hồ, và một enumerable rỗng là khác nhau từ một null. –

+4

Nếu bạn có quyền kiểm soát các phương thức 'GetEnumerable', bạn thực sự cần trả về các bộ sưu tập rỗng thay vì null. –

+0

@ DarrenYoung, tôi không thể kiểm soát được GetEnumerable. cộng với null được mong đợi trở lại. –

Trả lời

29
  1. Bạn sẽ có một overhead gọi phương thức, nó sẽ là không đáng kể, trừ khi bạn đang chạy nó trong một vòng lặp chặt chẽ hoặc một buổi biểu diễn kịch bản phê bình. Đó là một bóng tối so với một cái gì đó giống như một cuộc gọi cơ sở dữ liệu hoặc viết vào một hệ thống tập tin. Lưu ý rằng phương pháp này có lẽ sẽ không được gạch chân vì nó là một điều tra viên.
  2. Đó là tất cả về khả năng đọc/khả năng bảo trì. Tôi mong đợi điều gì sẽ xảy ra khi tôi thấy GetEnumerable().IgnoreIfEmpty().Sum();? Trong trường hợp này, nó có ý nghĩa.

Lưu ý rằng với C# 6, chúng tôi có thể sử dụng cú pháp sau: GetEnumerable()?.Sum() trả về int?. Bạn có thể viết GetEnumerable()?.Sum() ?? 0 hoặc GetEnumerable()?.Sum().GetValueOrDefault() để lấy số nguyên không null sẽ mặc định là 0.

Nếu bạn thực sự quan tâm đến hiệu suất, bạn cũng có thể tái cấu trúc lại phương pháp của mình để nó không phải là điều tra viên. Điều này có thể làm tăng nguy cơ nội tuyến, mặc dù tôi không có ý tưởng về logic 'phức tạp' của trình biên dịch JIT:

public static IEnumerable<T> IgnoreIfEmpty<T>(this IEnumerable<T> enumerable) 
{ 
    if (enumerable == null) return Enumerable.Empty<T>(); 
    return enumerable; 
} 

Tổng quát hơn về việc gia hạn LINQ, tôi nghĩ rằng đó là hoàn toàn tốt đẹp miễn là mã có ý nghĩa . MSDN thậm chí có an article về nó. Nếu bạn nhìn vào các phương thức tiêu chuẩn Where, Select trong LINQ, và quên đi các tối ưu hóa hiệu suất mà chúng có trong đó, các phương thức chủ yếu là tất cả các phương thức một lớp.

+0

xin lỗi tôi quên đề cập đến khung mục tiêu của tôi là 3.5 –

+0

'return enumerable;' không hoạt động trên mặt của tôi – Tyress

+0

@Tyress Lỗi là gì? –

40

Hình phạt nào được kết hợp với phương pháp tiện ích của tôi khi chạy?

Phương pháp mở rộng của bạn được chuyển thành máy trạng thái, vì vậy, chi phí tối thiểu cho điều đó, nhưng điều đó không đáng chú ý.

Có thực tiễn tốt để mở rộng LINQ theo cách đó không?

Trong câu hỏi của bạn, bạn nêu:

Trong khi làm việc với các phần mở rộng LINQ nó là bình thường để xem mã như thế này (chèn đếm được vô check here)

Và tôi cầu xin khác biệt . Thực tiễn phổ biến nói don't return null where an IEnumerable<T> is expected. Hầu hết các trường hợp phải trả về bộ sưu tập trống (hoặc IEnumerable), để lại null đến đặc biệt, vì null is not empty. Điều này sẽ làm cho phương pháp của bạn hoàn toàn thừa. Sử dụng Enumerable.Empty<T> nếu cần.

+11

Chắc chắn đồng ý với việc thích các bộ sưu tập trống hơn null. Null nên được sử dụng một cách tiết kiệm và rõ ràng, cho bất cứ điều gì, không chỉ là các bộ sưu tập. Mất số lượng bao nhiêu lỗi đến từ tham chiếu null. –

14

Bạn có thể bỏ qua phương pháp khuyến nông bổ sung và sử dụng null coalescing operator - đây là những gì nó cho, và một tấm séc một lần cho nullability nên được rất nhiều hiệu quả hơn một máy nhà nước:

IEnumerable<int> enumerable = GetEnumerable(); 
int sum = 0; 

sum = (enumerable ?? Enumerable.Empty<int>()).Sum(); 
+0

Vâng, khi chúng ta nói "hiệu quả hơn rất nhiều", chúng ta không thể nói nhiều hơn một phần nghìn giây, phải không? – Casey

+0

@Casey - Danh sách ban đầu càng lớn, tác động hiệu suất lớn hơn. –

+0

Hoặc trong C# 6, chỉ cần 'int sum = enumerable? .Sum() ?? 0'. – Mephy

-1

Hầu hết các lần chúng tôi viết rất nhiều mã chỉ vì chúng ta đang mê hoặc bởi vẻ đẹp của sự sáng tạo của chúng tôi - không phải vì chúng tôi thực sự cần nó - và sau đó chúng tôi gọi nó là trừu tượng, tái sử dụng, khả năng mở rộng, vv ..

là mảnh liệu này ít có thể đọc được hoặc ít có thể mở rộng hoặc ít có thể sử dụng lại hoặc chậm hơn:

var sum = GetEnumerable().Where(a => a != null).Sum(); 

Bạn viết ít mã hơn - mã ít bạn kiểm tra - hãy đơn giản hơn. BTW - bạn nên viết các phương thức mở rộng nếu bạn có thể biện minh cho nó.

+1

Tôi đồng ý với tuyên bố của bạn về việc giữ mọi thứ đơn giản ở mức độ nào đó, nhưng mã bạn đưa ra thực hiện điều gì đó rất khác với mã của câu hỏi: Bạn kiểm tra các phần tử là 'null', trong khi các câu hỏi sẽ kiểm tra nếu chính nó là' null '. – amulware

+0

@amulware có thể đếm được không được null - nếu nó là null thì nhà phát triển đang phá vỡ các thực hành tiêu chuẩn. Trả về các bộ sưu tập rỗng - không phải là rỗng. Nếu enumerable là null sau đó trở về - tại sao tính toán? Tham khảo: https://msdn.microsoft.com/en-us/library/dn169389(v=vs.110).aspx – akshaymishra14

+0

Tại sao câu trả lời của tôi bị bỏ qua - bất kỳ ai trong cụ thể có bất kỳ khiếu nại cụ thể nào? Hoặc thậm chí là miễn phí để downvote tất cả các phản ứng? – akshaymishra14

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