Почему Enumerable.Concat в том же IEnumerable идентифицируется как ошибка SonarCube? - PullRequest
3 голосов
/ 04 мая 2020

SonarQube определяет ошибку в моем коде на основе правила csharpsquid: S2114, и я не могу понять, как это относится к коду. Данный код объединяет значения IEnumerable из словаря Dictionary<string,object> attributes один раз за другим, например так:

var valuesTwice = attributes.Values.Concat(attributes.Values).ToArray();

Правило гласит:

Коллекции не должны быть переданные в качестве аргументов своим собственным методам

Передача коллекции в качестве аргумента собственному методу коллекции является либо ошибкой - предполагался какой-то другой аргумент - либо просто бессмысленным кодом.

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

Однако, насколько я понимаю, это не метод на самом деле список attributes.Values сам по себе, но метод расширения, поэтому рассматриваемый код может быть написан (на мой взгляд, менее элегантно), как вариант, добавленный ниже (оригинал включен для сравнения):

var valuesTwice = attributes.Values.Concat(attributes.Values).ToArray();
var valuesTwice = Enumerable.Concat(attributes.Values, attributes.Values).ToArray();

From читая страницу документации на Concat , я не вижу, как это утверждение может иметь непредвиденные последствия в словаре attributes, который, как я понимаю, является правилом для защиты. Это не похоже на то, как Concat изменяет структуру Values в Словаре.

Мое единственное объяснение состоит в том, что правила соответствия SonarQube путают этот метод расширения как метод для самой фактической коллекции. Безопасен ли этот Concat, и я могу просто проигнорировать это применение правила, или я что-то упускаю?

В качестве дополнительного вопроса: существует ли альтернативный (элегантный) способ достижения того же эффекта, производящий массив, в котором значения повторяются?

Обновление / уточнение: Моя проблема с описанием SonarQube заключается в отсутствии различия между передачей коллекции методу в самой коллекции (которая может иметь непреднамеренные побочные эффекты, о которых я думаю, это правило) и передача коллекции в качестве обоих аргументов методу расширения, см. stackoverflow.com/questions/100196/net-listt-concat-vs-addrange. Я считаю, что метод Concat не изменяет коллекцию, но возвращает новую коллекцию (точнее, перечисляемую), объединяющую две переданные коллекции. Я подвергаю сомнению, является ли Enumerable.Concat подходящим соответствием для правила, где я согласился бы, что метод AddRange: подача коллекции «со своим собственным хвостом» путем передачи ее в AddRange, у меня возникнет проблема, так как она изменяет коллекцию .

1 Ответ

0 голосов
/ 04 мая 2020

Обоснование проверки в SonarQube можно найти в их JIRA C# версии и JI C github PR). И это имеет смысл во многих сценариях ios.

Что касается бонусного вопроса, это вопрос предпочтений и, возможно, производительности (если код будет называться много), но вы можете попробовать что-то например:

var x = new[] {1,2};    
var times = 2;
x.SelectMany(i => Enumerable.Repeat(i, times)).ToList();

Он выдаст не тот же вывод, хотя ваш код вернет [1, 2, 1, 2], и это будет - [1, 1, 2, 2].

Вы также можете создать свой собственный метод расширения:

    public static IEnumerable<T> RepeatElements<T>(this IEnumerable<T> en, int times)
    {
        // check arguments
        var inner = en is ICollection<T> col ? col : en.ToList();
        foreach (var elem in inner)
        {
            for (int i = 0; i < times; i++)
            {
                yield return elem;
            }
        }
    }

Изменение порядка циклов, если важен порядок возврата элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...