2009-07-26 28 views
28

Cho một hệ thống phân cấp thừa kế đơn giản: Person -> Sinh viên, giáo viên, nhân viênLINQ: Từ một danh sách các loại T, lấy chỉ đối tượng của một lớp con nhất định S

Nói rằng tôi có một danh sách các người, L. Trong danh sách đó là một số sinh viên, giáo viên và nhân viên.

Sử dụng LINQ và C#, có cách nào tôi có thể viết một phương pháp chỉ có thể truy xuất một loại người cụ thể không?

Tôi biết tôi có thể làm điều gì đó như:

var peopleIWant = L.OfType<Teacher>(); 

Nhưng tôi muốn để có thể làm điều gì đó năng động hơn. Tôi muốn viết một phương thức sẽ lấy ra kết quả cho bất kỳ kiểu Person nào mà tôi có thể nghĩ đến, mà không cần phải viết một phương thức cho mọi kiểu có thể.

+1

Tại sao không tạo ra một phương pháp chung chung? –

+0

Tôi nghĩ đó là những gì Mladen Prajdic, đã làm. Tôi thậm chí không nghĩ về nó, nhưng bây giờ tôi thấy nó, nó có vẻ rất hợp lý. – Hythloth

Trả lời

41

bạn có thể làm điều này:

IList<Person> persons = new List<Person>(); 

public IList<T> GetPersons<T>() where T : Person 
{ 
    return persons.OfType<T>().ToList(); 
} 

IList<Student> students = GetPersons<Student>(); 
IList<Teacher> teacher = GetPersons<Teacher>(); 

EDIT: thêm các hạn chế nơi.

+0

Ah, điều này có vẻ tuyệt vời. Tôi mới đến LINQ, và không đặc biệt thành thạo trong generics, nhưng điều này có vẻ là chính xác những gì tôi muốn. Cảm ơn bạn!. – Hythloth

+0

Không cần phải gọi ToList trên kết quả của GetPersons , vì nó đã trả về một số ILIST ... –

+1

Bạn có thể muốn đặt một ràng buộc của "nơi T: Người" chỉ để tránh danh sách trống do lỗi chính tả, v.v. –

7

Điều này cần thực hiện thủ thuật.

var students = persons.Where(p => p.GetType() == typeof(Student)); 
+0

Cảm ơn bạn đã nhập. Tôi biết rằng một cái gì đó như thế này là có thể; Tôi muốn mở rộng ý tưởng cho một cái gì đó chung chung hơn. Mladen Prajdic đề nghị tôi sử dụng một phương pháp chung, đó là cái gì đó đã không vượt qua tâm trí của tôi. – Hythloth

2

Bạn có thể làm điều này:

IEnumerable<Person> GetPeopleOfType<T>(IEnumerable<Person> list) 
    where T : Person 
{ 
    return list.Where(p => p.GetType() == typeof(T)); 
} 

Nhưng tất cả các bạn đã thực sự làm là viết lại() phương pháp với một phiên bản an toàn hơn mà sử dụng loại tĩnh kiểm tra để đảm bảo bạn vượt qua trong một Person OfType LINQ của. Bạn vẫn không thể sử dụng phương thức này với một kiểu được xác định trong thời gian chạy (trừ khi bạn sử dụng sự phản chiếu).

Cho rằng, thay vì sử dụng Generics, bạn sẽ phải làm cho biến kiểu một tham số:

IEnumerable<Person> GetPeopleOfType(IEnumerable<Person> list, Type type) 
{ 
    if (!typeof(Person).IsAssignableFrom(type)) 
     throw new ArgumentException("Parameter 'type' is not a Person"); 

    return list.Where(p => p.GetType() == type); 
} 

Bây giờ bạn có thể xây dựng một số loại động và sử dụng nó để gọi phương pháp này.

+0

Cảm ơn bạn đã giới thiệu cho tôi những hạn chế "ở đâu" cho Generics. Ngay sau khi tôi đã xác định ràng buộc đó, bây giờ tôi có thể dựa vào sự hỗ trợ của Intellisense trên các phương thức và thuộc tính có sẵn của kiểu Person của tôi. – Hythloth

0

Đối với danh sách chung, sử dụng delegate:

public List<T> FilterByType(List<T> items, Type filterType) 
{ 
    return items.FindAll(delegate(T t) 
    { 
     return t.GetType() == filterType; 
    }); 
} 
Các vấn đề liên quan