2012-02-01 29 views
8

Làm cách nào để lọc ra các đối tượng dựa trên loại có nguồn gốc của chúng với các đối tượng LINQ?Loại trừ các loại biểu mẫu IEnumerable với linq

Tôi đang tìm giải pháp có hiệu suất tốt nhất.

Các lớp sử dụng:

abstract class Animal { } 
class Dog : Animal { } 
class Cat : Animal { } 
class Duck : Animal { } 
class MadDuck : Duck { } 

tôi biết ba phương pháp: Sử dụng các từ khóa is, sử dụng phương pháp Except, và sử dụng các phương pháp OfType.

List<Animal> animals = new List<Animal> 
{ 
    new Cat(), 
    new Dog(), 
    new Duck(), 
    new MadDuck(), 
}; 

// Get all animals except ducks (and or their derived types) 
var a = animals.Where(animal => (animal is Duck == false)); 
var b = animals.Except((IEnumerable<Animal>)animals.OfType<Duck>()); 

// Other suggestions 
var c = animals.Where(animal => animal.GetType() != typeof(Duck)) 

// Accepted solution 
var d = animals.Where(animal => !(animal is Duck)); 
+2

Điều gì sẽ xảy ra nếu bạn có 'MadDuck', được thừa kế từ 'Vịt'? Có nên trả lại hay không? Và, btw, bạn đang cố gắng đạt được điều gì? Sử dụng 'is' và kiểm tra kiểu thời gian chạy có thể chỉ ra các vấn đề thiết kế. – Groo

+0

Câu hỏi hay. Trong trường hợp cụ thể này, tôi cũng muốn các lớp con của Vịt được loại trừ. Điều đó sẽ làm cho tùy chọn của tôi 'b' không hợp lệ khi chúng so sánh loại nhưng không phải là thừa kế. – Aphelion

+0

Về nhiệm vụ thứ hai của tôi: từ quan điểm của OOP, các phần khác của mã của bạn thường không nên quan tâm đến các loại đối tượng thực tế của bạn. Nên biết "càng ít càng tốt". Đó là lý do tại sao tôi tự hỏi tại sao bạn đang làm điều này. – Groo

Trả lời

9

Nếu bạn cũng muốn loại trừ các lớp con của Vịt, sau đó là is là tốt nhất. Bạn có thể rút ngắn mã để chỉ .Where(animal => !(animal is Duck));

Nếu không, đề nghị sll của GetType là tốt nhất

+0

Vì tôi muốn loại trừ các lớp con và đây là ký hiệu ngắn hơn và dễ đọc hơn, tôi đã chấp nhận câu trả lời của bạn. – Aphelion

+0

Tôi không tin rằng nhịp điệu này của OfType (). – Will

4
  • Giải pháp sử dụng Except() là khá nặng.
  • Hãy ghi nhớ rằng giải pháp is - sẽ trở lại đúng ngay cả một số SomeDuck lớp kế thừa từ Duck

    class SomeDuck : Duck 
    ... 
    // duck is Duck == true 
    var duck = new SomeDuck(); 
    

Một giải pháp khác có thể là:

animals.Where(animal => animal.GetType() != typeof(Duck)) 
+1

Cảm ơn bạn. Tôi đã đưa đề xuất của bạn vào câu hỏi. – Aphelion

1

Nếu bạn không muốn Duck hay bất kỳ lớp con của Duck để được trả lại, bạn cần phải sử dụng phương pháp IsAssignableFrom:

animals.Where(animal => !animal.GetType().IsAssignableFrom(typeof(Duck))); 
+0

Rất đẹp. Tôi chưa bao giờ sử dụng 'IsAssignableFrom' trước đây. Tôi tự hỏi rằng hiệu suất là cho phương pháp này. Âm thanh như một trường hợp tốt cho một số hồ sơ. – Aphelion

+0

Tôi hy vọng nó sẽ nhanh như một 'như' bỏ rồi kiểm tra null. –

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