2013-03-01 26 views
9

Trong dự án của tôi, tôi có MyClass triển khai IMyClass. Tôi cần trả lại danh sách IMyClass bằng cách chuyển đổi danh sách các mục khác. Vì mục đích đơn giản, giả sử rằng tôi có thể tạo một MyClass chỉ bằng cách chuyển một mục khác vào hàm tạo của nó, tức là new MyClass(item).Tôi có nên bỏ vào trang lambda của mình hoặc bỏ IEnumerable không?

Hãy xem xét hai dòng sau đây, trong đó (như xa như tôi biết) tạo ra kết quả tương tự:

var option1 = items.Select(item => new MyClass(item)).Cast<IMyClass>().ToList() 
var option2 = items.Select(item => new MyClass(item) as IMyClass).ToList() 

Dường như với tôi rằng tùy chọn # 1 sẽ đòi hỏi một liệt kê đôi, một lần để đúc tất cả các mục vào giao diện của tôi và một lần để tạo danh sách. Nếu tôi đúng thì tùy chọn # 2 sẽ thông minh hơn. Tuy nhiên, tôi đã không bao giờ thấy bất kỳ mã nào sử dụng một cái gì đó như tùy chọn # 2 và tôi có xu hướng giả định rằng tôi không đủ thông minh để tìm ra thứ gì đó thông minh mà phần còn lại của cộng đồng C# không.

Trên một lưu ý phụ, tôi nghĩ rằng tùy chọn # 2 mang tính thẩm mỹ hơn, nhưng đó chỉ là tôi.

Câu hỏi của tôi là: là tùy chọn # 2 của tôi là một ý tưởng hay hơn như tôi nghĩ? Có bất kỳ gotchas tôi đang thiếu hoặc lý do khác tại sao tôi muốn dính vào với tùy chọn # 1? Hay tôi có lẽ so sánh hai ý tưởng ngu ngốc khi có một ý tưởng thứ ba thông minh hơn mà tôi đang thiếu hoàn toàn?

+3

Đừng quên rằng số đếm là lười biếng và có thể tổng hợp! Tùy chọn 1 sẽ không làm cho nó được liệt kê hai lần ... –

+0

Tại sao bạn cần truyền nếu 'MyClass' triển khai' IMyClass'? –

+1

Bạn biết bạn luôn có thể đánh vần các loại mà không suy luận? Tức là 'var result = items.Select (x => new MyClass (x)). ToList();' Điều này sẽ trả về 'IEnumerable ' :) –

Trả lời

17

tôi muốn đi cho tùy chọn 3:

var option3 = items.Select<Foo, IMyClass>(item => new MyClass(item)) 
        .ToList() 

Ngoài ra, không sử dụng as nhưng chỉ đúc thường:

var option4 = items.Select(item => (IMyClass) new MyClass(item)) 
        .ToList() 

Cả hai loại này đều sạch hơn sử dụng Cast.

Oh, và như C# 4 với .NET 4 (do hiệp phương sai), bạn có thể đặt một đối số kiểu trên ToList cuộc gọi thay vì:

var option5 = items.Select(item => new MyClass(item)) 
        .ToList<IMyClass>() 
+0

Tùy chọn 3 và 4 đã không làm điều đó cho tôi về mặt thẩm mỹ, nhưng tùy chọn 5 chắc chắn có. Hoan hô cho sự lựa chọn! – ean5533

+0

Không nên chọn tùy chọn 4 là 'var option4 = items.Select (item => (** IMyClass **) new MyClass (item))'? – pescolino

+0

@pescolino: Có thực sự - cố định, cảm ơn. –

3

Dường như với tôi rằng tùy chọn # 1 sẽ đòi hỏi một liệt kê đôi

Điều này không đúng. Trong cả hai trường hợp, bộ sưu tập items chỉ được liệt kê khi bạn truy cập vào ToList().

Dòng

var option1 = items.Select(item => new MyClass(item)).Cast<IMyClass>().ToList() 

tương đương với

var option1 = items.Select(item => new MyClass(item)).Select(x => (IMyClass)x).ToList() 

Sự khác biệt duy nhất giữa hai là người đầu tiên yêu cầu hai chức năng gọi mỗi món (trừ C# inlines các lambdas bằng cách nào đó, mà tôi không tin là trường hợp) trong khi tùy chọn thứ hai chỉ yêu cầu một.

Cá nhân, tôi muốn làm việc thứ hai là vấn đề về phong cách.

+0

+1. Lý do cá nhân của tôi để chọn 2 - Tôi không thích 'Cast' trong bối cảnh như vậy. Nó cho thấy rằng người ta không thể quyết định những thứ gì để đưa vào bộ sưu tập. Lưu ý rằng trong nhiều trường hợp nếu bạn không cần loại 'List ' cụ thể, bạn có thể sử dụng 'IEnumerable ' ở những nơi có yêu cầu 'IEnumerable ' - vì vậy bạn có thể cần phải cast trong một số trường hợp . –

1

Loại nào bạn sử dụng là vấn đề ưa thích, điều chúng tôi thực sự không thể trả lời cho bạn.

Nhưng trực giác của bạn nếu sắp xếp chính xác rằng Cast thêm lớp lặp thứ hai vào vòng lặp của bạn. Nó rất nhỏ, và tôi nghi ngờ nó sẽ tạo ra sự khác biệt nào đo lường trong hoạt động, nhưng phương pháp Cast trả về một đối tượng mới IEnumerable rằng về cơ bản thực hiện điều này:

foreach (object obj in source) yield return (TResult)obj; 

Tác dụng chủ yếu là khác mức trên các cuộc gọi stack; vì nó sử dụng yield, nó sẽ chỉ lặp theo yêu cầu, giống như hầu hết các phương thức khác IEnumerable. Nhưng nó sẽ phải trả về mặc dù hai cấp trạng thái của trình lặp thay vì một. Cho dù điều đó có quan trọng với bạn hay không là thứ bạn cần để đo lường cho các ứng dụng của riêng bạn.

(Cũng lưu ý rằng, ít nhất là theo các nguồn tài liệu tham khảo, nó là một diễn viên không an toàn, mà thể ném một ngoại lệ nếu các diễn viên không hợp lệ. Đó là một lý do để thích lựa chọn của bạn 2 #.)

1

Bạn luôn có thể cung cấp luận cứ loại rõ ràng để Chọn bạn

var option2 = items.Select<IItem,IMyClass>(item => new MyClass(item)).ToList(); 

trong đó IItem là loại hoặc giao diện cho mục nào có thể truyền.

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