2010-06-22 12 views
7

Zastanawiam się, czy możliwe jest usunięcie wszystkich obiektów tego samego rodzaju z ogólnej listy przy użyciu metod rozszerzeń. coś takiego kodu:Usunąć obiekty określonego rodzaju z listy <T> w języku C# za pomocą metod rozszerzających?

public static Remove<T>(this List<[any type]> list) 
{ 
    // some code to remove the objects of type T from the list 
} 

mogę to zrobić za pomocą następującego kodu:

public static Remove<T, K>(this List<K> list) 
{ 
    // some code to remove the objects of type T from the List<K> 
} 

ale chcę po prostu użyć typu (t), bez potrzeby dodawania jakichkolwiek typ K. przez robi, że użytkownik może korzystać z tej metody rozszerzenie po prostu napisać to:

List<object> list = new List<object>(); 
list.Add(1); 
list.Add("text"); 

// remove all int type objects from the list 
list.Remove<int>(); 

metoda rozszerzenie, które można użyć, aby zrobić coś dokładnie jak wyżej kod jest co naprawdę muszę tutaj.

pozdrawiam

Odpowiedz

7

Nie wiem, czy to będzie działać czy nie ... ale warto spróbować (nie mogę skompilować, aby dokładnie sprawdzić czy):

public static void Remove<T>(this IList list) 
{ 
    if(list != null) 
    { 
     var toRemove = list.OfType<T>().ToList(); 

     foreach(var item in toRemove) 
      list.Remove(item); 
    } 
} 

Lub jeśli potrzebujesz czegoś bardziej rygorystyczne (zamiast dowolnego obiektu, który można rzucić na typ), możesz spróbować:

public static void Remove<T>(this IList list) 
{ 
    if(list != null) 
    { 
     var toRemove = list.Where(i => typeof(i) == typeof(T)).ToList(); 

     foreach(var item in toRemove) 
      list.Remove(item); 
    } 
} 

Teoretycznie powinieneś być gotowy. List<T> implementuje IList, która implementuje IEnumerable. IList dostarcza Remove(), a IEnumerable zapewnia metodę rozszerzenia.

Należy pamiętać, że może to z pewnością spowodować nieoczekiwane wyniki w zależności od typów w kolekcji. Zgadzam się z Jonem Skeetem ... to zdecydowanie brzydkie.

+0

, więc nie musimy już podawać typów zwracanych; o) –

+0

OfType zwróci każdy obiekt, który może być rzutowany na typ. To może usunąć zbyt wiele elementów ... –

+0

Działa z kilkoma poprawkami :) –

0

Co starasz się zrobić, to mieć typ pracy wnioskowania o jeden typu parametru, ale z drugiej strony wyraźnie określić. Obawiam się, że C# na to nie pozwala.

Formularz wykorzystujący nietypowy podany przez Justina będzie działał, ponieważ ma tylko jeden parametr typu (typ elementu do usunięcia). Jest to dość brzydkie.

Czy jest to coś, czego tak często potrzebujesz na tyle często, że obawiasz się podania obu argumentów typu?

3

Czy należy podać typ filtra jako rodzajowy?

public static IEnumerable<T> Remove<T>(this IEnumerable<T> items, 
              Type removeThese) 
{ 
    return items.Where(i => !removeThese.IsInstanceOfType(i)); 
} 

// usage 
var newSet = mylist.Remove(typeof(int)); 
+0

Err, to będzie po prostu produkować 'IEnumerable ', który reprezentuje wszystkie elementy * nie * Spośród określony typ. Nie wiem, jak to działa w pierwotnym celu PO. –

+0

Nie widziałem typu zwrotu, więc założyłem, że chce, aby łańcuch łączył ze sobą obiekty. Jeśli chcesz tylko usunąć element bez zwrotu, zobacz odpowiedź Justina –

1

Nie polecam tego, ponieważ wygląda na to, że API będzie bardzo trudne do zrozumienia i utrzymania.

Biorąc to pod uwagę, co następuje powinno działać:

public static void Remove<T>(this IList list) 
{ 
    Type type = typeof(T); 
    var itemsToRemove = list.Cast<object>.Where(o => o.GetType() == type).ToList(); 
    foreach(var item in itemsToRemove) 
    { 
      list.Remove(item); 
    } 
} 
+0

Dlaczego wywołać 'ToList'? – StriplingWarrior

+2

@StriplingWarrior: musisz ocenić zapytanie LINQ, lub potencjalnie wyrzuci wyjątek po usunięciu elementu, ponieważ nadal będziesz go oceniać podczas edytowania kolekcji. –

+0

Dobra odpowiedź. Dzięki. – StriplingWarrior

0

Co naprawdę chcesz zrobić, to mieć metodę rozszerzenia tak:

public static void Remove<T>(this IList list) 
{ 
    // Cycle through everything, comparing the types. 
    for (int index = list.Count; index >= 0; --index) 
    { 
     // Get the object. 
     object item = list[index]; 

     // If the item is null, continue. 
     if (item == null) continue; 

     // Remove the item if the types match. 
     if (typeof(T) == item.GetType()) list.RemoveAt(index); 
    } 
} 

pamiętać, że można użyć tego tylko dla List<T> , ponieważ implementuje nietypowy interfejs IList. Interfejs IList<T> ma wartość , a nie pochodzącą z nie-ogólnego interfejsu IList.

+0

Metoda rozszerzenia wymaga słowa kluczowego 'this' przed pierwszym parametrem. – StriplingWarrior

0

Oto kolejny wariant. Zwrot używany tylko w przypadku, gdy chcesz powiązać metodę.

public static List<TList> Remove<TList, TRemove>(this List<TList> list) 
{ 
    list.RemoveAll(item => item is TRemove); 
    return list; 
} 
-1

dzięki greate odpowiedź Justin Niessner udało mi się to zrobić za pomocą następującego kodu:

public static void Remove<T>(this IList list) 
{ 
    ArrayList deleteList = new ArrayList(); 

    foreach (var item in list) 
     if (item.GetType() == typeof(T)) 
      deleteList.Add(item); 

    for (int i = 0; i < deleteList.Count; i++) 
     list.Remove(deleteList[i]);   
} 

w Justin Niessner odpowiedź jest jeden problem. nie można usunąć elementu enumatora w bloku foreach.

0

to pewnie zrobić coś takiego:

enumerable.Cast<object>().Where(o => !(o is T)) 

i pominąć faktu, że lista jest przeliczalny. (Przesyła się tutaj, aby upewnić się, że jeśli działa, jeśli już masz ogólny przelicznik, możesz go pominąć)

0

Powtórz listę i usuń te, które pasują do niepożądanego typu.

public static void RemoveAllOfType<T>(this IList list) 
{ 
    for(int index = list.Count - 1; index >= 0; index --) 
    { 
     if(list[index] is T) 
     { 
      list.RemoveAt(index); 
     } 
    } 
} 

Jeśli zawsze będzie za pomocą List<object> można uprościć trochę więcej.

public static void RemoveAllOfType<T>(this List<object> list) 
{ 
    list.RemoveAll(item => item is T); 
} 

Happy Coding!

0

Nie wiem, czy to zrobi

static class test 
    { 
     public static void RemAll<T>(this List<Object> self, T t) where T : Type 
     { 
      self.RemoveAll(x => x.GetType()==t); 
     } 
    } 

mogą być uznane za poniżej

static void Main(string[] args) 
     { 
      List<object> ll = new List<object>() { 1, 2, "abcd", "xyz", 22.3, 900, "junk" }; 
      ll.RemAll(typeof(int)); 
      ll.ForEach(x => Console.WriteLine(x)); 
     } 
Powiązane problemy