2009-02-02 24 views
20

Tôi có mộtLàm cách nào để truyền một Danh sách <T> hiệu quả?

List<InputField> 

nhưng tôi cần một

List<IDataField> 

Có cách nào để cast này trong C#? Hoặc sử dụng LINQ để có được kết quả tương tự?

Tôi có hai lớp mà thực hiện cùng một giao diện:

interface IDataField { } 
class InputField : IDataField { } 
class PurchaseField : IDataField { } 

Danh sách này xuất phát từ một truy vấn LINQ-to-SQL:

List<InputField> list = (from i .... select i).ToList(); 
+0

Hmm, maby nó là thông minh hơn để tìm ra lý do tại sao bạn cần một danh sách các InputField thay vì một danh sách IDataField ở nơi đầu tiên? Hoặc là nó thực sự cần thiết? –

+0

Tôi nghĩ là cần thiết. InputField và PurchaseField là hai thứ riêng biệt có hai điểm chung. IDataField thể hiện điều đó. Tôi có một số logic phức tạp mà chỉ hoạt động trên IDataField. – bentford

+0

Lưu ý cho tất cả mọi người: đây là những câu trả lời thực sự tốt! Cảm ơn đã phản ứng nhanh chóng!!! – bentford

Trả lời

36

Cả .OfType <T> và .Cast <T> sẽ trả về một danh sách các T, nhưng ý nghĩa của hai phương pháp là khác nhau.

list.OfType lọc danh sách gốc và trả về tất cả các mục thuộc loại T và bỏ qua những mục không thuộc loại đó.

list.Cast phôi tất cả các mục trong danh sách gốc để nhập T và ném ngoại lệ cho các mục không thể truyền sang loại đó.

Trong trường hợp của bạn cả hai sẽ cho kết quả tương tự, nhưng sử dụng .Cast sẽ truyền đạt ý định của bạn rõ ràng hơn rất nhiều, vì vậy tôi khuyên bạn nên sử dụng điều đó.

List<InputField> list = (from i .... select i).Cast<IDataField>.ToList(); 
+0

Chết tiệt - đánh bại tôi trong 35 giây. Upvoted - đây là câu trả lời đúng vì OP đang tìm kiếm một dàn diễn viên. –

+0

Tôi chấp nhận câu trả lời này bởi vì tôi đã thực sự tìm kiếm một diễn viên. Cảm ơn tất cả mọi người. – bentford

11
List<InputField> raw = (from i .... select i).ToList(); 
List<IDataField> result = raw.OfType<IDataField>().ToList(); 
1

Tôi không biết rằng một cast trực tiếp sẽ có hiệu quả mong muốn. Một vài lần hiếm hoi tôi đã làm điều này, nó thường là một cái gì đó như:

List<InputField> list = ..... 
List<IDataField> list2 = new (List<IDataField>((IDataField[])list.ToArray())); 
4

Kể từ khi danh sách được đến từ

List<InputField> list = (from i .... select i).ToList(); 

Không thể bạn chỉ cần khắc phục "chọn tôi" một phần để thay trở lại IDataField thay thế? Something như thế này:

List<InputField> list = (from i .... select (IDataField)i).ToList(); 

Nếu điều đó không làm việc, có lẽ là "Diễn viên" mở rộng IEnumerable sẽ làm việc:

List<DataField> list2 = list.Cast<IDataField>(); 
+0

Thực tế việc khắc phục phần "chọn" của truy vấn sẽ là tốt nhất. Nếu không, hãy nhìn vào câu trả lời của Helen Toomik về sự khác biệt giữa OfType và Cast ... –

6

Bạn cũng có thể sử dụng List.ConvertAll.

Tài liệu: http://msdn.microsoft.com/en-us/library/73fe8cwf.aspx

Ví dụ:

List<IDataField> newList = oldList.ConvertAll(i => i as IDataField); 
+2

Chỉ là những gì tôi định nói. Lưu ý rằng trong C# 2.0 bạn cần phải xác định rõ ràng chung chung, nhưng trong C# 3.0 (như trên) nó được suy ra. –

3

Chỉ trong trường hợp: Tôi đã ít C# kinh nghiệm, nhưng nếu xây dựng chung này có nghĩa là điều tương tự nó trong Java, sau đó bạn phải tạo một danh sách hoàn toàn mới parametrized bởi supertype.Nói cách khác, nếu mọi trường hợp của Bangle cũng là một phiên bản của Akthud, thì không theo sau mỗi List<Bangle> cũng là List<Akthud>.

Lý do cho điều này là bạn có thể có hai tham chiếu đến số List<Bangle> này. Nếu tham chiếu thứ hai phôi và sau đó gọi nó là List<Akthud>, thì nó được phép thêm Akthud vào nó - nhưng bây giờ tham chiếu đầu tiên có một số List<Bangle> có thành viên không phải là tất cả Bangle s. Sự vi phạm!

Điều đó đang được nói, câu trả lời của David B thực sự nên làm những gì bạn muốn, chính xác, AFAICT. (Nó trông giống như một hoạt động sao chép.)

[Và nếu tôi là sự hiểu lầm ngữ nghĩa của C Generics #, tôi hy vọng ai đó sửa chữa cho tôi trong một bình luận!]

+0

Bạn đúng - generics trong C# không phải là biến thể cũng không phải là biến thể; một cái gì đó họ đang sửa chữa trong C# 4. Đây là một bài viết trên MSDN giải thích này: http://msdn.microsoft.com/en-us/library/ms228359(VS.80).aspx –

+0

Liên kết tốt đẹp. Tôi nghĩ rằng bạn có nghĩa là điều này như là một minh họa của vấn đề biến thể chung chung, chứ không phải là sự thay đổi C# 4 (tôi thấy không có gì về điều đó). Chỉ để được rõ ràng(?). Vẫn còn rất nhiều thông tin, tuy nhiên. –

1

ConvertAll có vẻ như một giải pháp tốt hơn, vì nó doesn 't phụ thuộc vào thư viện LINQ và ngắn hơn và trực quan hơn.

Nhưng cả hai cách giải quyết thay vì giải pháp. Cả hai người trong số họ tạo ra một bộ sưu tập mới với cùng một dữ liệu. Nên có một sự hỗ trợ cho hiệp phương sai chung trong .net, tức là upcasting trong bộ sưu tập chung chung, cho phép bạn làm điều đó một cách tự nhiên. Ví dụ:

List<IDataField> ls = (List<IDataField>)List<InputField> 

Từ tìm kiếm của tôi cho đến nay, kết luận của tôi là .Net không hỗ trợ tính năng này. Do đó chúng ta phải kết thúc với cách giải quyết.

Đây là những cuộc thảo luận về chủ đề này:

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