2012-01-25 33 views
7

Ngoài khả năng đọc, sự khác biệt giữa các truy vấn LINQ sau và là những gì khi nào và tại sao tôi sẽ sử dụng một trong khác:Sự khác nhau giữa OfType <>() và kiểm tra gõ vào đâu() mở rộng

IEnumerable<T> items = listOfItems.Where(d => d is T).Cast<T>(); 

IEnumerable<T> items = listOfItems.OfType<T>(); 

cập nhật: Đằng, xin lỗi giới thiệu một số lỗi khi cố gắng đơn giản hóa vấn đề của tôi

+3

Sự khác biệt là người đầu tiên sẽ không biên dịch, phải không? – Krizz

+1

Có thể có nghĩa là: 'listOfItems.Where (d => d là T) .Cố ()' – codekaizen

+1

Mã cập nhật của bạn vẫn không biên dịch. Bạn không thể chỉ sử dụng 'IEnumerable ' tới 'T' và gán nó cho 'IEnumerable '. – svick

Trả lời

8

Chúng ta hãy so sánh ba phương pháp (chú ý đến lập luận chung chung):

  1. listOfItems.Where(t => t is T) kêu gọi IEnumerable<X> vẫn sẽ trở lại IEnumerable<X> chỉ lọc để chỉ chứa các yếu tố của các loại T.

  2. listOfItems.OfType<T>() kêu gọi IEnumerable<X> sẽ trở lại IEnumerable<T> yếu tố chứa có thể được đúc để gõ T.

  3. listOfItems.Cast<T>() kêu gọi IEnumerable<X> sẽ trở lại IEnumerable<T> yếu tố chứa đúc gõ T hoặc ném một ngoại lệ nếu có những yếu tố không thể chuyển đổi.

listOfItems.Where(d => d is T).Cast<T>() về cơ bản là làm điều tương tự hai lần - Where lọc tất cả các yếu tố đó là T nhưng vẫn giữ kiểu IEnumerable<X> và sau đó một lần nữa Cast cố gắng đúc họ T nhưng lần này trở về IEumerable<T>.

+0

Sigh ... đã cố gắng đơn giản hóa câu hỏi nhưng cuối cùng lại đưa ra một lỗi. Đã cập nhật thành 'IEnumerable'. – ajbeaven

+0

@ajbeaven ok, loại bỏ một phần câu trả lời chỉ ra điều này cho dòng thứ hai, nhưng vẫn - dòng đầu tiên là không chính xác. – Krizz

+0

@Krizz. Dòng đầu tiên không chính xác như thế nào? Có vẻ như một điều hợp lệ muốn dàn diễn viên để xem xét các yếu tố trong danh sách sẽ thuộc loại T – dreza

2

listOfItems.Where(d => d is T) trả lại một IEnumerable<U> (trong đó U là loại mục trong listOfItems), chỉ chứa các mục thuộc loại T.

listOfItems.OfType<T>() trả về một IEnumerable<T>.

1

Về cơ bản, không có sự khác biệt với biên soạn cấu hình thời gian chạy được biên dịch của mã được biên dịch. OfType<T> trả lại số OfTypeIterator mà nội bộ thực hiện kiểm tra isyield return những kết quả phù hợp.

+0

Không có sự khác biệt trong mã biên dịch ... thực sự? Có lẽ bạn nên suy nghĩ lại về nó;). Ngay cả kiểu trả về cũng không giống nhau ... –

+0

Về đặc điểm của thời gian chạy ... về cơ bản chúng giống nhau, mặc dù các kiểu khác nhau. Hơn nữa, tôi trả lời mã dự định của người hỏi, chứ không phải những gì anh ta đăng. – codekaizen

+1

Đó là chức năng gần như giống nhau, nhưng nó biên dịch một cái gì đó khá khác nhau, do đó, câu đầu tiên của bạn là đồng bằng sai ... –

3

Nếu tôi mất một vài quyền tự do với ví dụ của bạn và quây nó ra trong LINQPad, đây là những gì tôi nhận được:

Phương pháp

List<T> GetNumbers<T>(List<T> nums){ 
    return nums.Where(d => d is T).ToList<T>(); 
} 

List<T> GetNumbersOfType<T>(List<T> nums){ 
    return nums.OfType<T>().ToList<T>(); 
} 

IL

GetNumbers: 
IL_0000: ldarg.1  
IL_0001: ldnull  
IL_0002: ldftn  05 00 00 2B 
IL_0008: newobj  0A 00 00 0A 
IL_000D: call  06 00 00 2B 
IL_0012: call  07 00 00 2B 
IL_0017: ret   

GetNumbersOfType: 
IL_0000: ldarg.1  
IL_0001: call  08 00 00 2B 
IL_0006: call  07 00 00 2B 
IL_000B: ret 

tôi 'không phải là chuyên gia IL, nhưng nó trông giống như phương pháp GetNumbers (sử dụngCú pháp) tạo một đối tượng mới mỗi lần qua vòng lặp, và vì vậy có thể tiêu tốn bộ nhớ nhiều hơn một chút so với phương thức GetNumbersOfType (sử dụng OfType).

+3

Không nhất thiết. Các câu lệnh 'call' gọi ra những gì ở đây là các phương thức không xác định (và khác nhau), có thể có các tác động hoàn toàn khác với thời gian và không gian chạy được chỉ định với tập hợp IL này. Vì cả hai 'Where' và' OfType' tạo một đối tượng iterator mới, tôi đoán là 'Where' được inlined. – codekaizen

+1

Sự khác biệt trong IL là người đầu tiên tạo ra một đại biểu. Tôi nghĩ rằng điều đó nên được mong đợi, đó là những gì mã nói, sau khi tất cả. – svick

+1

@codekaizen, nội dung liên quan đến điều này như thế nào? Có chắc chắn không có nội tuyến đang diễn ra trong IL. Nói chung, trình biên dịch C# không làm nội tuyến, trình biên dịch JIT làm. – svick

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