Майкрософт.Ошибка ремонтопригодности с методами расширения списка

#c# #list #.net-3.5 #extension-methods #windows-ce

#c# #Список #.net-3.5 #методы расширения #windows-ce

Вопрос:

Итак, я попытался создать некоторые базовые методы расширения для List . По сути, у меня есть UniqueAdd и UniqueAddRange. Он проверит наличие значения перед добавлением, и если оно уже есть в списке, оно его не добавит. Вот код:

 public static class ListExtensions
{
    /// <summary>
    /// Adds only the values in the 'values' collection that do not already exist in the list. Uses list.Contains() to determine existence of
    /// previous values.
    /// </summary>
    /// <param name="list"></param>
    /// <param name="values"></param>
    public static void UniqueAddRange<T>(this List<T> list, IEnumerable<T> values)
    {
        foreach (T value in values)
        {
            list.UniqueAdd(value);
        }
    }

    /// <summary>
    /// Adds the value to the list only if it does not already exist in the list. Uses list.Contains() to determine existence of previos values.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="value"></param>
    public static void UniqueAdd<T>(this List<T> list, T value)
    {
        if (!list.Contains(value))
        {
            list.Add(value);
        }
    }
}
  

И я получаю следующую ошибку при сборке:

 CA0001 : Rule=Microsoft.Maintainability#CA1506, Target=Some.Namespace.ListExtensions : Collection was modified; enumeration operation may not execute.
  

Вот ссылка на ошибку, но я не уверен, как исправить мои методы расширения, учитывая эту информацию. В нем говорится, что

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

Кто-нибудь знает, почему я получаю эту ошибку и как исправить мои методы расширения, чтобы они не нарушали это правило?

Спасибо!

PS: Прежде чем кто-либо упомянет об этом, я рассмотрел возможность использования HashSet, но HashSet не существует в compact framework.

Ответ №1:

Я думаю, что ваш код вызвал ошибку в FxCop, «Коллекция была изменена» — это классический упс. Затем он решил, что его ошибка была вашей проблемой, стиль catch (исключение).

Ищите обновление. Тот, который я использую, не жалуется на ваш код (версия VS2010).

Комментарии:

1. Психическая отладка не часто приветствуется: (

Ответ №2:

Он сообщает вам, что вы меняете список при его перечислении. Это ясно из вашего кода (вы добавляете в список одновременно с перечислением).

Как насчет:

 public static void UniqueAddRange<T>(this List<T> list, IEnumerable<T> values)
{
    list.AddRange(values.Except(list));
}
  

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

Комментарии:

1. Спасибо, я попробую. Я забыл, что Contains будет непреднамеренно перечислять список, поэтому я получаю эту проблему. Что касается HashSet, я упомянул в своем сообщении, что он не существует в compact framework.

2. Нет, вы видите эту проблему, потому что цикл foreach в UniqueAddRange повторяет перечисление, которое изменяется под его ногами. Заметил проблему с набором хэшей, отсюда и зачеркивание 😉 Способ LINQ также должен быть быстрее, потому что ему не нужно проверять весь список для каждой вставки.

3. Я не думаю, что это правильно: values и list — это два полностью отдельных списка, и я только повторяю values , я никогда не изменяю его. Я только изменяю list .

4. Ах, да. Мой плохой. Я должен идти спать сейчас, так как я бесполезен! Рискну предположить, что предоставленный мной код, вероятно, более эффективен. Похоже, @Hans может быть прав.

5. Я не сомневаюсь, что в полном объеме . NET framework это так, но, на удивление, compact framework работает довольно медленно с LINQ.