2010-12-30 12 views
19

Tôi đang cố gắng đưa ra một triển khai cho NotOfType, có cú pháp cuộc gọi có thể đọc được. NotOfType nên là bổ sung cho OfType<T> và do đó sẽ mang lại tất cả các yếu tố đó là không loại TLàm cách nào để triển khai NotOfType <T> trong LINQ có cú pháp gọi điện đẹp mắt?

Mục tiêu của tôi là để thực hiện một phương pháp mà sẽ được gọi là giống như OfType<T>, giống như trong dòng cuối cùng của đoạn này:

public abstract class Animal {} 
public class Monkey : Animal {} 
public class Giraffe : Animal {} 
public class Lion : Animal {} 

var monkey = new Monkey(); 
var giraffe = new Giraffe(); 
var lion = new Lion(); 

IEnumerable<Animal> animals = new Animal[] { monkey, giraffe, lion }; 

IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>(); 

Tuy nhiên, tôi không thể đưa ra triển khai hỗ trợ cú pháp gọi cụ thể đó.

Đây là những gì tôi đã cố gắng cho đến nay:

public static class EnumerableExtensions 
{ 
    public static IEnumerable<T> NotOfType<T>(this IEnumerable<T> sequence, Type type) 
    { 
     return sequence.Where(x => x.GetType() != type); 
    } 

    public static IEnumerable<T> NotOfType<T, TExclude>(this IEnumerable<T> sequence) 
    { 
     return sequence.Where(x => !(x is TExclude)); 
    } 
} 

Gọi các phương pháp này sẽ trông như thế này:

// Animal is inferred 
IEnumerable<Animal> fewerAnimals = animals.NotOfType(typeof(Giraffe)); 

// Not all types could be inferred, so I have to state all types explicitly 
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Animal, Giraffe>(); 

Tôi nghĩ rằng có rất lớn những hạn chế với phong cách của cả hai cuộc gọi này. Việc đầu tiên bị một dự phòng "loại/loại" xây dựng, và thứ hai chỉ là không có ý nghĩa (tôi muốn có một danh sách các loài động vật không phải là động vật cũng không Giraffes?).

Vì vậy, có cách nào để thực hiện những gì tôi muốn không? Nếu không, nó có thể được có thể trong các phiên bản tương lai của ngôn ngữ? (Tôi nghĩ rằng có thể một ngày nào đó chúng ta sẽ đặt tên đối số kiểu, hoặc rằng chúng ta chỉ cần cung cấp một cách rõ ràng các đối số kiểu không thể suy ra được?)

Hoặc tôi chỉ là ngớ ngẩn?

+0

Tôi chỉ viết framework/chia sẻ mã như thế này nếu tôi cảm thấy nó sẽ có được một lượng tái sử dụng hợp lý. Bao lâu thì bạn cần một phương pháp như thế này, và nó có biện minh cho chi phí (thời gian dành cho việc suy nghĩ về những khó khăn về thiết kế) không? –

+1

Hai phiên bản của bạn làm những việc khác nhau đáng kể. – SLaks

+0

@SLaks: Xây dựng, vui lòng. –

Trả lời

10

Làm thế nào về

animals.NotOf(typeof(Giraffe)); 

Ngoài ra, you can split the generic parameters across two methods:

animals.NotOf().Type<Giraffe>(); 

public static NotOfHolder<TSource> NotOf<TSource>(this IEnumerable<TSource> source); 

public class NotOfHolder<TSource> : IHideObjectMembers { 
    public IEnumerable<TSource> NotOf<TNot>(); 
} 

Ngoài ra, bạn cần phải quyết định xem có nên cũng loại trừ các loại di truyền.

+0

Ah. Cách tiếp cận "thông thạo" này trông giống như một giải pháp thay thế tốt. –

+0

Tôi đã viết một bài đăng trên blog giải thích chi tiết hơn: http://blog.slaks.net/2010/12/partial-type-inference-in-net.html – SLaks

+0

Cuối cùng, tôi đã kết luận rằng giải pháp của bạn sẽ là tốt nhất cho kịch bản cụ thể của tôi. Tôi sẽ tính đến thực tế là mã sẽ được sử dụng trong các thử nghiệm chấp nhận tự động và có thể một số người có thể không phải là nhà phát triển toàn thời gian đọc được một lúc nào đó. Có một cuộc gọi được gõ mạnh mẽ tất cả các cách sẽ làm cho nó dễ dàng hơn để giữ cho mã tiếp theo nhiều hơn (human-) có thể đọc được. Cảm ơn. –

5

Điều này có vẻ giống như một đề xuất lạ, nhưng phương pháp mở rộng trên đồng bằng cũ IEnumerable thì sao? Điều này sẽ phản ánh chữ ký của OfType<T> và nó cũng sẽ loại bỏ vấn đề của các tham số loại <T, TExclude> dư thừa.

Tôi cũng cho rằng nếu bạn có một chuỗi được đánh máy mạnh, đã có rất ít lý do cho phương thức đặc biệt NotOfType<T>; dường như có nhiều khả năng hữu ích hơn (trong tâm trí của tôi) để loại trừ một loại cụ thể khỏi một chuỗi tùy ý loại ... hoặc để tôi đặt theo cách này: nếu bạn đang xử lý một số IEnumerable<T>, điều này là tầm thường để gọi Where(x => !(x is T)) ; tính hữu ích của một phương thức như NotOfType<T> trở nên có vấn đề hơn trong trường hợp này.

+0

Ý tưởng thú vị về IEnumerable không chung chung. Nó sẽ làm cho mã gọi điện thoại trông chính xác như tôi muốn. Rõ ràng, nó sẽ không trả về một chuỗi được đánh máy mạnh, đó là một sự bất tiện nhỏ. –

+0

* Về đoạn 2: * Một * có thể * cho rằng tính hữu ích của 'NotOfType ' khớp với 'OfType ' ...(Thật thú vị khi cố gắng áp dụng các đối số của bạn vào 'OfType '.) Đối số của tôi chỉ là về khả năng đọc mã. FYI, trong trường hợp kinh doanh thực tế, tôi có một chuỗi các thành phần 'Event' có các kiểu con khác nhau, và trong một kịch bản cụ thể, các yêu cầu được gọi cho một danh sách tất cả các sự kiện, ngoại trừ một kiểu cụ thể. Thử nghiệm này là tất cả về việc tìm cách thể hiện yêu cầu đó trong mã dễ đọc. –

+1

@Lette: 'OfType ()' khác vì nó thay đổi loại chuỗi. 'NotOfType' không thể thay đổi kiểu chuỗi. – SLaks

25

Tôi không chắc chắn lý do tại sao bạn không chỉ nói:

animals.Where(x => !(x is Giraffe)); 

Điều này có vẻ hoàn toàn có thể đọc được với tôi.Nó chắc chắn là thẳng về phía trước với tôi hơn animals.NotOfType<Animal, Giraffe>() mà sẽ gây nhầm lẫn cho tôi nếu tôi đi qua nó ... người đầu tiên sẽ không bao giờ nhầm lẫn tôi vì nó là ngay lập tức có thể đọc được.

Nếu bạn muốn có một giao diện thông thạo, tôi giả sử bạn cũng có thể làm một cái gì đó như thế này với một phương pháp ngữ mở rộng trên Object:

animals.Where(x => x.NotOfType<Giraffe>()) 
1

Nếu bạn đang đi để thực hiện một phương pháp suy luận, bạn muốn suy luận tất cả các cách. Điều đó đòi hỏi một ví dụ về từng loại:

public static class ExtMethods 
{ 
    public static IEnumerable<T> NotOfType<T, U>(this IEnumerable<T> source) 
    { 
     return source.Where(t => !(t is U)); 
    } 
     // helper method for type inference by example 
    public static IEnumerable<T> NotOfSameType<T, U>(
     this IEnumerable<T> source, 
     U example) 
    { 
     return source.NotOfType<T, U>(); 
    } 
} 

gọi bằng

List<ValueType> items = new List<ValueType>() { 1, 1.0m, 1.0 }; 
IEnumerable<ValueType> result = items.NotOfSameType(2); 
0

Tôi chỉ cố gắng này và nó hoạt động ...

public static IEnumerable<TResult> NotOfType<TExclude, TResult>(this IEnumerable<TResult> sequence) 
    => sequence.Where(x => !(x is TExclude)); 

Tôi có thiếu cái gì?

+0

Nó không phải là nó không _work_. Phản đối của tôi là bạn cần phải chỉ định cả hai loại ('TSource',' TResult') cho cuộc gọi chung và chỉ _looks_ lạ đối với cuộc gọi cụ thể này. –

+0

Tôi đồng ý nó trông lạ ... – franklores

0

Bạn có thể xem xét việc này

public static IEnumerable NotOfType<TResult>(this IEnumerable source) 
{ 
    Type type = typeof(Type); 

    foreach (var item in source) 
    { 
     if (type != item.GetType()) 
     { 
      yield return item; 
     } 
    } 
} 
0

Tôi đã có một vấn đề tương tự, và đã xem qua câu hỏi này trong khi tìm kiếm một câu trả lời.

tôi thay vì giải quyết cho các cú pháp gọi sau đây:

var fewerAnimals = animals.Except(animals.OfType<Giraffe>()); 

Nó đã bất lợi mà nó liệt kê bộ sưu tập hai lần (do đó không thể được sử dụng với một chuỗi vô hạn), nhưng ưu điểm là không có chức năng trợ giúp mới là yêu cầu, và ý nghĩa là rõ ràng.

Trong trường hợp sử dụng thực tế của tôi, tôi cũng đã kết thúc thêm một .Where(...) sau .OfType<Giraffe>() (hươu cao cổ cũng bao gồm trừ khi họ đáp ứng một điều kiện loại trừ cụ thể mà chỉ có ý nghĩa đối với hươu cao cổ)

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