Удалите объекты некоторого типа из Списка <T> в C# с помощью дополнительных методов?

Интересно если его возможное для удаления всех объектов из того же вида из универсального Списка с помощью дополнительных методов. что-то вроде этого кодирует:

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

Я могу сделать это при помощи следующего кода:

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

но я хочу просто использовать на типе (T) без потребности указать любой тип K. путем выполнения, что пользователь может использовать этот дополнительный метод просто записью это:

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

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

дополнительный метод, который я могу использовать, чтобы сделать что-то точно как вышеупомянутый код, - то, в чем я действительно нуждаюсь здесь.

с уважением

8
задан Incognito 22 June 2010 в 19:53
поделиться

10 ответов

Не уверен, сработает это или нет ... но попробовать стоит (я не могу скомпилировать, чтобы перепроверить):

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);
    }
}

Или, если вам нужно что-то более строгое (а не любой объект, который может быть приведение к типу), вы можете попробовать:

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);
    }
}

Теоретически все должно быть в порядке. List реализует IList , который реализует IEnumerable . IList предоставляет Remove () , а IEnumerable предоставляет метод расширения.

Имейте в виду, что это определенно может привести к неожиданным результатам в зависимости от типов в коллекции. Я согласен с Джоном Скитом ... это определенно уродливо.

7
ответ дан 5 December 2019 в 17:34
поделиться

Нужно ли вам указывать тип фильтра как общий?

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));
3
ответ дан 5 December 2019 в 17:34
поделиться

Я не рекомендую это, так как это похоже на API, который будет очень сложно понять и поддерживать.

При этом должно работать следующее:

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);
     }
}
1
ответ дан 5 December 2019 в 17:34
поделиться

Вы пытаетесь сделать так, чтобы вывод типов работал на одном параметре типа, а другой указывался явно. Боюсь, что C# этого не позволяет.

Форма, использующая негенеративный IList, приведенная Джастином, будет работать, потому что у нее только один параметр типа (тип элемента для удаления). Однако это довольно уродливо.

Это то, что вам действительно нужно настолько часто, что вы беспокоитесь об указании обоих аргументов типа?

0
ответ дан 5 December 2019 в 17:34
поделиться

Вот еще один вариант. Возврат используется только в том случае, если требуется сцепить метод.

public static List<TList> Remove<TList, TRemove>(this List<TList> list)
{
    list.RemoveAll(item => item is TRemove);
    return list;
}
0
ответ дан 5 December 2019 в 17:34
поделиться

Я бы, вероятно, сделал что-то вроде:

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

И пропустил тот факт, что enumerable - это список. (Приведение здесь используется, чтобы убедиться, что где работает, если у вас уже есть универсальное перечислимое значение, вы можете его пропустить)

0
ответ дан 5 December 2019 в 17:34
поделиться

благодаря великому ответу Джастина Нисснера мне удалось сделать это, используя следующий код:

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]);        
}

в ответе Джастина Нисснера есть одна проблема. вы не можете удалить элемент перечисления в блоке foreach.

-1
ответ дан 5 December 2019 в 17:34
поделиться

Сделайте шаг назад по списку и удалите те, которые соответствуют нежелательному типу.

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 );
        }
    }
}

Если вы всегда будете использовать List, вы можете еще немного упростить ситуацию.

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

Счастливого кодинга!

0
ответ дан 5 December 2019 в 17:34
поделиться

Не уверен, что это подойдет

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

Может быть вызвано как показано ниже

  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));
        }
0
ответ дан 5 December 2019 в 17:34
поделиться

Что вы действительно хотите сделать, так это иметь метод расширения, подобный этому:

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);
    } 
}

Обратите внимание, что вы можете использовать это только для List, поскольку он реализует негенерический интерфейс IList. Интерфейс IList не вытекает из негенеративного интерфейса IList.

0
ответ дан 5 December 2019 в 17:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: